Bug 895747 - DevTools Net Panel: cannot inspect contents of some POST messages, r=rcampbell

This commit is contained in:
Victor Porof
2014-02-13 15:15:42 -05:00
parent 9767ff6679
commit 20dbdd1cd5
7 changed files with 255 additions and 34 deletions

View File

@@ -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;
}

View File

@@ -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]

View 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();
});
}

View File

@@ -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);
});
});

View File

@@ -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";

View 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>

View File

@@ -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.
});