Bug 895747 - DevTools Net Panel: cannot inspect contents of some POST messages, r=rcampbell
This commit is contained in:
@@ -55,8 +55,7 @@ const GENERIC_VARIABLES_VIEW_SETTINGS = {
|
||||
editableNameTooltip: "",
|
||||
preventDisableOnChange: true,
|
||||
preventDescriptorModifiers: true,
|
||||
eval: () => {},
|
||||
switch: () => {}
|
||||
eval: () => {}
|
||||
};
|
||||
const NETWORK_ANALYSIS_PIE_CHART_DIAMETER = 200; // px
|
||||
|
||||
@@ -2101,32 +2100,45 @@ NetworkDetailsView.prototype = {
|
||||
if (!aHeadersResponse || !aPostDataResponse) {
|
||||
return promise.resolve();
|
||||
}
|
||||
return gNetwork.getString(aPostDataResponse.postData.text).then(aString => {
|
||||
// Handle query strings (poor man's forms, e.g. "?foo=bar&baz=42").
|
||||
let cType = aHeadersResponse.headers.filter(({ name }) => name == "Content-Type")[0];
|
||||
let cString = cType ? cType.value : "";
|
||||
if (cString.contains("x-www-form-urlencoded") ||
|
||||
aString.contains("x-www-form-urlencoded")) {
|
||||
let formDataGroups = aString.split(/\r\n|\n|\r/);
|
||||
for (let group of formDataGroups) {
|
||||
this._addParams(this._paramsFormData, group);
|
||||
}
|
||||
}
|
||||
// Handle actual forms ("multipart/form-data" content type).
|
||||
else {
|
||||
// This is really awkward, but hey, it works. Let's show an empty
|
||||
// scope in the params view and place the source editor containing
|
||||
// the raw post data directly underneath.
|
||||
$("#request-params-box").removeAttribute("flex");
|
||||
let paramsScope = this._params.addScope(this._paramsPostPayload);
|
||||
paramsScope.expanded = true;
|
||||
paramsScope.locked = true;
|
||||
return gNetwork.getString(aPostDataResponse.postData.text).then(aPostData => {
|
||||
let contentTypeHeader = aHeadersResponse.headers.filter(({ name }) => name == "Content-Type")[0];
|
||||
let contentTypeLongString = contentTypeHeader ? contentTypeHeader.value : "";
|
||||
|
||||
$("#request-post-data-textarea-box").hidden = false;
|
||||
return NetMonitorView.editor("#request-post-data-textarea").then(aEditor => {
|
||||
aEditor.setText(aString);
|
||||
});
|
||||
}
|
||||
return gNetwork.getString(contentTypeLongString).then(aContentType => {
|
||||
let urlencoded = "x-www-form-urlencoded";
|
||||
|
||||
// Handle query strings (poor man's forms, e.g. "?foo=bar&baz=42").
|
||||
if (aContentType.contains(urlencoded)) {
|
||||
let formDataGroups = aPostData.split(/\r\n|\r|\n/);
|
||||
for (let group of formDataGroups) {
|
||||
this._addParams(this._paramsFormData, group);
|
||||
}
|
||||
}
|
||||
// Handle actual forms ("multipart/form-data" content type).
|
||||
else {
|
||||
// This is really awkward, but hey, it works. Let's show an empty
|
||||
// scope in the params view and place the source editor containing
|
||||
// the raw post data directly underneath.
|
||||
$("#request-params-box").removeAttribute("flex");
|
||||
let paramsScope = this._params.addScope(this._paramsPostPayload);
|
||||
paramsScope.expanded = true;
|
||||
paramsScope.locked = true;
|
||||
|
||||
$("#request-post-data-textarea-box").hidden = false;
|
||||
return NetMonitorView.editor("#request-post-data-textarea").then(aEditor => {
|
||||
// Most POST bodies are usually JSON, so they can be neatly
|
||||
// syntax highlighted as JS. Otheriwse, fall back to plain text.
|
||||
try {
|
||||
JSON.parse(aPostData);
|
||||
aEditor.setMode(Editor.modes.js);
|
||||
} catch (e) {
|
||||
aEditor.setMode(Editor.modes.text);
|
||||
} finally {
|
||||
aEditor.setText(aPostData);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}).then(() => window.emit(EVENTS.REQUEST_POST_PARAMS_DISPLAYED));
|
||||
},
|
||||
|
||||
@@ -2147,8 +2159,8 @@ NetworkDetailsView.prototype = {
|
||||
paramsScope.expanded = true;
|
||||
|
||||
for (let param of paramsArray) {
|
||||
let headerVar = paramsScope.addItem(param.name, {}, true);
|
||||
headerVar.setGrip(param.value);
|
||||
let paramVar = paramsScope.addItem(param.name, {}, true);
|
||||
paramVar.setGrip(param.value);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -2591,14 +2603,16 @@ nsIURL.store = new Map();
|
||||
*/
|
||||
function parseQueryString(aQueryString) {
|
||||
// Make sure there's at least one param available.
|
||||
if (!aQueryString || !aQueryString.contains("=")) {
|
||||
// Be careful here, params don't necessarily need to have values, so
|
||||
// no need to verify the existence of a "=".
|
||||
if (!aQueryString) {
|
||||
return;
|
||||
}
|
||||
// Turn the params string into an array containing { name: value } tuples.
|
||||
let paramsArray = aQueryString.replace(/^[?&]/, "").split("&").map(e =>
|
||||
let (param = e.split("=")) {
|
||||
name: NetworkHelper.convertToUnicode(unescape(param[0])),
|
||||
value: NetworkHelper.convertToUnicode(unescape(param[1]))
|
||||
name: param[0] ? NetworkHelper.convertToUnicode(unescape(param[0])) : "",
|
||||
value: param[1] ? NetworkHelper.convertToUnicode(unescape(param[1])) : ""
|
||||
});
|
||||
return paramsArray;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ support-files =
|
||||
html_json-text-mime-test-page.html
|
||||
html_jsonp-test-page.html
|
||||
html_navigate-test-page.html
|
||||
html_params-test-page.html
|
||||
html_post-data-test-page.html
|
||||
html_post-raw-test-page.html
|
||||
html_simple-test-page.html
|
||||
@@ -35,9 +36,10 @@ support-files =
|
||||
[browser_net_charts-04.js]
|
||||
[browser_net_charts-05.js]
|
||||
[browser_net_clear.js]
|
||||
[browser_net_complex-params.js]
|
||||
[browser_net_content-type.js]
|
||||
[browser_net_copy_url.js]
|
||||
[browser_net_copy_image_as_data_uri.js]
|
||||
[browser_net_copy_url.js]
|
||||
[browser_net_cyrillic-01.js]
|
||||
[browser_net_cyrillic-02.js]
|
||||
[browser_net_filter-01.js]
|
||||
|
||||
148
browser/devtools/netmonitor/test/browser_net_complex-params.js
Normal file
148
browser/devtools/netmonitor/test/browser_net_complex-params.js
Normal file
@@ -0,0 +1,148 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests whether complex request params and payload sent via POST are
|
||||
* displayed correctly.
|
||||
*/
|
||||
|
||||
function test() {
|
||||
initNetMonitor(PARAMS_URL).then(([aTab, aDebuggee, aMonitor]) => {
|
||||
info("Starting test... ");
|
||||
|
||||
let { document, L10N, EVENTS, Editor, NetMonitorView } = aMonitor.panelWin;
|
||||
let { RequestsMenu, NetworkDetails } = NetMonitorView;
|
||||
|
||||
RequestsMenu.lazyUpdate = false;
|
||||
NetworkDetails._params.lazyEmpty = false;
|
||||
|
||||
Task.spawn(function () {
|
||||
yield waitForNetworkEvents(aMonitor, 0, 6);
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" },
|
||||
document.getElementById("details-pane-toggle"));
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" },
|
||||
document.querySelectorAll("#details-pane tab")[2]);
|
||||
|
||||
yield waitFor(aMonitor.panelWin, EVENTS.REQUEST_POST_PARAMS_DISPLAYED);
|
||||
yield testParamsTab1('a', '""', '{ "foo": "bar" }', '""');
|
||||
|
||||
RequestsMenu.selectedIndex = 1;
|
||||
yield waitFor(aMonitor.panelWin, EVENTS.REQUEST_POST_PARAMS_DISPLAYED);
|
||||
yield testParamsTab1('a', '"b"', '{ "foo": "bar" }', '""');
|
||||
|
||||
RequestsMenu.selectedIndex = 2;
|
||||
yield waitFor(aMonitor.panelWin, EVENTS.REQUEST_POST_PARAMS_DISPLAYED);
|
||||
yield testParamsTab1('a', '"b"', 'foo', '"bar"');
|
||||
|
||||
RequestsMenu.selectedIndex = 3;
|
||||
yield waitFor(aMonitor.panelWin, EVENTS.REQUEST_POST_PARAMS_DISPLAYED);
|
||||
yield testParamsTab2('a', '""', '{ "foo": "bar" }', "js");
|
||||
|
||||
RequestsMenu.selectedIndex = 4;
|
||||
yield waitFor(aMonitor.panelWin, EVENTS.REQUEST_POST_PARAMS_DISPLAYED);
|
||||
yield testParamsTab2('a', '"b"', '{ "foo": "bar" }', "js");
|
||||
|
||||
RequestsMenu.selectedIndex = 5;
|
||||
yield waitFor(aMonitor.panelWin, EVENTS.REQUEST_POST_PARAMS_DISPLAYED);
|
||||
yield testParamsTab2('a', '"b"', '?foo=bar', "text");
|
||||
|
||||
yield teardown(aMonitor);
|
||||
finish();
|
||||
});
|
||||
|
||||
function testParamsTab1(
|
||||
aQueryStringParamName, aQueryStringParamValue, aFormDataParamName, aFormDataParamValue)
|
||||
{
|
||||
let tab = document.querySelectorAll("#details-pane tab")[2];
|
||||
let tabpanel = document.querySelectorAll("#details-pane tabpanel")[2];
|
||||
|
||||
is(tabpanel.querySelectorAll(".variables-view-scope").length, 2,
|
||||
"The number of param scopes displayed in this tabpanel is incorrect.");
|
||||
is(tabpanel.querySelectorAll(".variable-or-property").length, 2,
|
||||
"The number of param values displayed in this tabpanel is incorrect.");
|
||||
is(tabpanel.querySelectorAll(".variables-view-empty-notice").length, 0,
|
||||
"The empty notice should not be displayed in this tabpanel.");
|
||||
|
||||
is(tabpanel.querySelector("#request-params-box")
|
||||
.hasAttribute("hidden"), false,
|
||||
"The request params box should not be hidden.");
|
||||
is(tabpanel.querySelector("#request-post-data-textarea-box")
|
||||
.hasAttribute("hidden"), true,
|
||||
"The request post data textarea box should be hidden.");
|
||||
|
||||
let paramsScope = tabpanel.querySelectorAll(".variables-view-scope")[0];
|
||||
let formDataScope = tabpanel.querySelectorAll(".variables-view-scope")[1];
|
||||
|
||||
is(paramsScope.querySelector(".name").getAttribute("value"),
|
||||
L10N.getStr("paramsQueryString"),
|
||||
"The params scope doesn't have the correct title.");
|
||||
is(formDataScope.querySelector(".name").getAttribute("value"),
|
||||
L10N.getStr("paramsFormData"),
|
||||
"The form data scope doesn't have the correct title.");
|
||||
|
||||
is(paramsScope.querySelectorAll(".variables-view-variable .name")[0].getAttribute("value"),
|
||||
aQueryStringParamName,
|
||||
"The first query string param name was incorrect.");
|
||||
is(paramsScope.querySelectorAll(".variables-view-variable .value")[0].getAttribute("value"),
|
||||
aQueryStringParamValue,
|
||||
"The first query string param value was incorrect.");
|
||||
|
||||
is(formDataScope.querySelectorAll(".variables-view-variable .name")[0].getAttribute("value"),
|
||||
aFormDataParamName,
|
||||
"The first form data param name was incorrect.");
|
||||
is(formDataScope.querySelectorAll(".variables-view-variable .value")[0].getAttribute("value"),
|
||||
aFormDataParamValue,
|
||||
"The first form data param value was incorrect.");
|
||||
}
|
||||
|
||||
function testParamsTab2(
|
||||
aQueryStringParamName, aQueryStringParamValue, aRequestPayload, aEditorMode)
|
||||
{
|
||||
let tab = document.querySelectorAll("#details-pane tab")[2];
|
||||
let tabpanel = document.querySelectorAll("#details-pane tabpanel")[2];
|
||||
|
||||
is(tabpanel.querySelectorAll(".variables-view-scope").length, 2,
|
||||
"The number of param scopes displayed in this tabpanel is incorrect.");
|
||||
is(tabpanel.querySelectorAll(".variable-or-property").length, 1,
|
||||
"The number of param values displayed in this tabpanel is incorrect.");
|
||||
is(tabpanel.querySelectorAll(".variables-view-empty-notice").length, 0,
|
||||
"The empty notice should not be displayed in this tabpanel.");
|
||||
|
||||
is(tabpanel.querySelector("#request-params-box")
|
||||
.hasAttribute("hidden"), false,
|
||||
"The request params box should not be hidden.");
|
||||
is(tabpanel.querySelector("#request-post-data-textarea-box")
|
||||
.hasAttribute("hidden"), false,
|
||||
"The request post data textarea box should not be hidden.");
|
||||
|
||||
let paramsScope = tabpanel.querySelectorAll(".variables-view-scope")[0];
|
||||
let payloadScope = tabpanel.querySelectorAll(".variables-view-scope")[1];
|
||||
|
||||
is(paramsScope.querySelector(".name").getAttribute("value"),
|
||||
L10N.getStr("paramsQueryString"),
|
||||
"The params scope doesn't have the correct title.");
|
||||
is(payloadScope.querySelector(".name").getAttribute("value"),
|
||||
L10N.getStr("paramsPostPayload"),
|
||||
"The request payload scope doesn't have the correct title.");
|
||||
|
||||
is(paramsScope.querySelectorAll(".variables-view-variable .name")[0].getAttribute("value"),
|
||||
aQueryStringParamName,
|
||||
"The first query string param name was incorrect.");
|
||||
is(paramsScope.querySelectorAll(".variables-view-variable .value")[0].getAttribute("value"),
|
||||
aQueryStringParamValue,
|
||||
"The first query string param value was incorrect.");
|
||||
|
||||
return NetMonitorView.editor("#request-post-data-textarea").then((aEditor) => {
|
||||
is(aEditor.getText(), aRequestPayload,
|
||||
"The text shown in the source editor is incorrect.");
|
||||
is(aEditor.getMode(), Editor.modes[aEditorMode],
|
||||
"The mode active in the source editor is incorrect.");
|
||||
|
||||
teardown(aMonitor).then(finish);
|
||||
});
|
||||
}
|
||||
|
||||
aDebuggee.performRequests();
|
||||
});
|
||||
}
|
||||
@@ -55,6 +55,7 @@ function test() {
|
||||
"baz", "The second query param name was incorrect.");
|
||||
is(postScope.querySelectorAll(".variables-view-variable .value")[1].getAttribute("value"),
|
||||
"\"123\"", "The second query param value was incorrect.");
|
||||
|
||||
teardown(aMonitor).then(finish);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -22,6 +22,7 @@ const CYRILLIC_URL = EXAMPLE_URL + "html_cyrillic-test-page.html";
|
||||
const STATUS_CODES_URL = EXAMPLE_URL + "html_status-codes-test-page.html";
|
||||
const POST_DATA_URL = EXAMPLE_URL + "html_post-data-test-page.html";
|
||||
const POST_RAW_URL = EXAMPLE_URL + "html_post-raw-test-page.html";
|
||||
const PARAMS_URL = EXAMPLE_URL + "html_params-test-page.html";
|
||||
const JSONP_URL = EXAMPLE_URL + "html_jsonp-test-page.html";
|
||||
const JSON_LONG_URL = EXAMPLE_URL + "html_json-long-test-page.html";
|
||||
const JSON_MALFORMED_URL = EXAMPLE_URL + "html_json-malformed-test-page.html";
|
||||
|
||||
54
browser/devtools/netmonitor/test/html_params-test-page.html
Normal file
54
browser/devtools/netmonitor/test/html_params-test-page.html
Normal file
@@ -0,0 +1,54 @@
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Network Monitor test page</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p>Request params type test</p>
|
||||
|
||||
<script type="text/javascript">
|
||||
function post(aAddress, aQuery, aContentType, aPostBody) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", aAddress + aQuery, true);
|
||||
xhr.setRequestHeader("content-type", aContentType);
|
||||
xhr.send(aPostBody);
|
||||
}
|
||||
|
||||
function performRequests() {
|
||||
var urlencoded = "application/x-www-form-urlencoded";
|
||||
|
||||
setTimeout(function() {
|
||||
post("baz", "?a", urlencoded, '{ "foo": "bar" }');
|
||||
|
||||
setTimeout(function() {
|
||||
post("baz", "?a=b", urlencoded, '{ "foo": "bar" }');
|
||||
|
||||
setTimeout(function() {
|
||||
post("baz", "?a=b", urlencoded, '?foo=bar');
|
||||
|
||||
setTimeout(function() {
|
||||
post("baz", "?a", undefined, '{ "foo": "bar" }');
|
||||
|
||||
setTimeout(function() {
|
||||
post("baz", "?a=b", undefined, '{ "foo": "bar" }');
|
||||
|
||||
setTimeout(function() {
|
||||
post("baz", "?a=b", undefined, '?foo=bar');
|
||||
|
||||
// Done.
|
||||
}, 10);
|
||||
}, 10);
|
||||
}, 10);
|
||||
}, 10);
|
||||
}, 10);
|
||||
}, 10);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -15,6 +15,7 @@
|
||||
function post(aAddress, aMessage, aCallback) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", aAddress, true);
|
||||
xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded");
|
||||
|
||||
xhr.onreadystatechange = function() {
|
||||
if (this.readyState == this.DONE) {
|
||||
@@ -25,7 +26,7 @@
|
||||
}
|
||||
|
||||
function performRequests() {
|
||||
var rawData = "Content-Type: application/x-www-form-urlencoded\r\n\r\nfoo=bar&baz=123";
|
||||
var rawData = "foo=bar&baz=123";
|
||||
post("sjs_simple-test-server.sjs", rawData, function() {
|
||||
// Done.
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user