зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1758361 - [devtools] Fix crash when viewing request headers from upload stream r=nchevobbe
This patch fixes 2 crashes, for different reasons and improves/ adds tests to cover the issues - The raw view of the `Request headers for upload stream` crashes when there is only one header sent. This is covered by the scenario ``` [ "content-type: application/x-www-form-urlencoded\r", "\r", "\r", "foo=bar&baz=123" ] ``` - The Request side panel crashes when there is no form data body content added to the payload sent. This is covered in the test by the scenario ``` [ "content-type: application/x-www-form-urlencoded\r", "\r", "\r", ] ``` Differential Revision: https://phabricator.services.mozilla.com/D143339
This commit is contained in:
Родитель
42b7d01933
Коммит
0a4230aa64
|
@ -386,9 +386,11 @@ class HeadersPanel extends Component {
|
|||
|
||||
let rows;
|
||||
if (value) {
|
||||
const match = value.match(/\n/g);
|
||||
rows = match !== null ? match.length : 0;
|
||||
// Need to add 1 for the horizontal scrollbar
|
||||
// not to cover the last row of raw data
|
||||
rows = value.match(/\n/g).length + 1;
|
||||
rows = rows + 1;
|
||||
}
|
||||
|
||||
return tr(
|
||||
|
|
|
@ -53,7 +53,7 @@ async function getFormDataSections(
|
|||
const postDataLongString = postData.postData.text;
|
||||
const text = await getLongString(postDataLongString);
|
||||
|
||||
for (const section of text.split(/\r\n|\r|\n/)) {
|
||||
for (const section of text.trim().split(/\r\n|\r|\n/)) {
|
||||
// Before displaying it, make sure this section of the POST data
|
||||
// isn't a line containing upload stream headers.
|
||||
if (payloadHeaders.every(header => !section.startsWith(header.name))) {
|
||||
|
@ -359,7 +359,7 @@ function parseQueryString(query) {
|
|||
*/
|
||||
function parseFormData(sections) {
|
||||
if (!sections) {
|
||||
return null;
|
||||
return [];
|
||||
}
|
||||
|
||||
return sections
|
||||
|
|
|
@ -21,103 +21,180 @@ add_task(async function() {
|
|||
store.dispatch(Actions.batchEnable(false));
|
||||
|
||||
// Execute requests.
|
||||
await performRequests(monitor, tab, 1);
|
||||
await performRequests(monitor, tab, 3);
|
||||
|
||||
// Wait for all tree view updated by react
|
||||
let wait = waitForDOM(document, "#headers-panel .accordion-item", 3);
|
||||
const expectedRequestsContent = [
|
||||
{
|
||||
headersFromUploadSectionTitle:
|
||||
"Request headers from upload stream (47 B)",
|
||||
uploadSectionHeaders: [
|
||||
{ label: "content-type", value: "application/x-www-form-urlencoded" },
|
||||
],
|
||||
uploadSectionRawText: "content-type: application/x-www-form-urlencoded",
|
||||
requestPanelFormData: [
|
||||
{ label: "foo", value: '"bar"' },
|
||||
{ label: "baz", value: '"123"' },
|
||||
],
|
||||
requestPanelPayload: [
|
||||
"content-type: application/x-www-form-urlencoded",
|
||||
"foo=bar&baz=123",
|
||||
],
|
||||
},
|
||||
{
|
||||
headersFromUploadSectionTitle:
|
||||
"Request headers from upload stream (47 B)",
|
||||
uploadSectionHeaders: [
|
||||
{ label: "content-type", value: "application/x-www-form-urlencoded" },
|
||||
],
|
||||
uploadSectionRawText: "content-type: application/x-www-form-urlencoded",
|
||||
requestPanelPayload: ["content-type: application/x-www-form-urlencoded"],
|
||||
},
|
||||
{
|
||||
headersFromUploadSectionTitle:
|
||||
"Request headers from upload stream (74 B)",
|
||||
uploadSectionHeaders: [
|
||||
{ label: "content-type", value: "application/x-www-form-urlencoded" },
|
||||
{ label: "custom-header", value: "hello world!" },
|
||||
],
|
||||
uploadSectionRawText:
|
||||
"content-type: application/x-www-form-urlencoded\r\ncustom-header: hello world!",
|
||||
requestPanelFormData: [
|
||||
{ label: "foo", value: '"bar"' },
|
||||
{ label: "baz", value: '"123"' },
|
||||
],
|
||||
requestPanelPayload: [
|
||||
"content-type: application/x-www-form-urlencoded",
|
||||
"custom-header: hello world!",
|
||||
"foo=bar&baz=123",
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const requests = document.querySelectorAll(".request-list-item");
|
||||
store.dispatch(Actions.toggleNetworkDetails());
|
||||
clickOnSidebarTab(document, "headers");
|
||||
await wait;
|
||||
|
||||
let tabpanel = document.querySelector("#headers-panel");
|
||||
is(
|
||||
tabpanel.querySelectorAll(".accordion-item").length,
|
||||
3,
|
||||
"There should be 3 header sections displayed in this tabpanel."
|
||||
);
|
||||
for (let i = 0; i < expectedRequestsContent.length; i++) {
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" }, requests[i]);
|
||||
await assertRequestContentInHeaderAndRequestSidePanels(
|
||||
expectedRequestsContent[i]
|
||||
);
|
||||
}
|
||||
|
||||
is(
|
||||
tabpanel.querySelectorAll(".accordion-item .accordion-header-label")[2]
|
||||
.textContent,
|
||||
L10N.getStr("requestHeadersFromUpload") +
|
||||
" (" +
|
||||
L10N.getFormatStr("networkMenu.sizeB", 74) +
|
||||
")",
|
||||
"The request headers from upload section doesn't have the correct title."
|
||||
);
|
||||
async function assertRequestContentInHeaderAndRequestSidePanels(expected) {
|
||||
// Wait for all 3 headers sections to load (Response Headers, Request Headers, Request headers from upload stream)
|
||||
let wait = waitForDOM(document, "#headers-panel .accordion-item", 3);
|
||||
clickOnSidebarTab(document, "headers");
|
||||
await wait;
|
||||
|
||||
let labels = tabpanel.querySelectorAll("tr .treeLabelCell .treeLabel");
|
||||
let values = tabpanel.querySelectorAll("tr .treeValueCell .objectBox");
|
||||
let tabpanel = document.querySelector("#headers-panel");
|
||||
is(
|
||||
tabpanel.querySelectorAll(".accordion-item").length,
|
||||
3,
|
||||
"There should be 3 header sections displayed in this tabpanel."
|
||||
);
|
||||
|
||||
is(
|
||||
labels[labels.length - 2].textContent,
|
||||
"content-type",
|
||||
"The first request header name was incorrect."
|
||||
);
|
||||
is(
|
||||
values[values.length - 2].textContent,
|
||||
"application/x-www-form-urlencoded",
|
||||
"The first request header value was incorrect."
|
||||
);
|
||||
is(
|
||||
labels[labels.length - 1].textContent,
|
||||
"custom-header",
|
||||
"The second request header name was incorrect."
|
||||
);
|
||||
is(
|
||||
values[values.length - 1].textContent,
|
||||
"hello world!",
|
||||
"The second request header value was incorrect."
|
||||
);
|
||||
info("Check that the Headers in the upload stream section are correct.");
|
||||
is(
|
||||
tabpanel.querySelectorAll(".accordion-item .accordion-header-label")[2]
|
||||
.textContent,
|
||||
expected.headersFromUploadSectionTitle,
|
||||
"The request headers from upload section doesn't have the correct title."
|
||||
);
|
||||
|
||||
// Wait for raw data toggle to be displayed
|
||||
wait = waitForDOM(
|
||||
document,
|
||||
"#request-panel .raw-data-toggle-input .devtools-checkbox-toggle"
|
||||
);
|
||||
clickOnSidebarTab(document, "request");
|
||||
await wait;
|
||||
let labels = tabpanel.querySelectorAll(
|
||||
".accordion-item:last-child .accordion-content tr .treeLabelCell .treeLabel"
|
||||
);
|
||||
let values = tabpanel.querySelectorAll(
|
||||
".accordion-item:last-child .accordion-content tr .treeValueCell .objectBox"
|
||||
);
|
||||
|
||||
tabpanel = document.querySelector("#request-panel");
|
||||
for (let i = 0; i < labels.length; i++) {
|
||||
is(
|
||||
labels[i].textContent,
|
||||
expected.uploadSectionHeaders[i].label,
|
||||
"The request header name was incorrect."
|
||||
);
|
||||
is(
|
||||
values[i].textContent,
|
||||
expected.uploadSectionHeaders[i].value,
|
||||
"The request header value was incorrect."
|
||||
);
|
||||
}
|
||||
|
||||
ok(
|
||||
tabpanel.querySelector(".treeTable"),
|
||||
"The params tree view should be displayed."
|
||||
);
|
||||
ok(
|
||||
tabpanel.querySelector(".editor-mount") === null,
|
||||
"The post data shouldn't be displayed."
|
||||
);
|
||||
info(
|
||||
"Toggle to open the raw view for the request headers from upload stream"
|
||||
);
|
||||
|
||||
is(
|
||||
tabpanel.querySelector(".data-label").textContent,
|
||||
L10N.getStr("paramsFormData"),
|
||||
"The form data section doesn't have the correct title."
|
||||
);
|
||||
wait = waitForDOM(
|
||||
tabpanel,
|
||||
".accordion-item:last-child .accordion-content .raw-headers-container"
|
||||
);
|
||||
tabpanel.querySelector("#raw-upload-checkbox").click();
|
||||
await wait;
|
||||
|
||||
labels = tabpanel.querySelectorAll("tr .treeLabelCell .treeLabel");
|
||||
values = tabpanel.querySelectorAll("tr .treeValueCell .objectBox");
|
||||
const rawTextArea = tabpanel.querySelector(
|
||||
".accordion-item:last-child .accordion-content .raw-headers"
|
||||
);
|
||||
is(
|
||||
rawTextArea.textContent,
|
||||
expected.uploadSectionRawText,
|
||||
"The raw text for the request headers from upload section is correct"
|
||||
);
|
||||
|
||||
is(
|
||||
labels[0].textContent,
|
||||
"foo",
|
||||
"The first payload param name was incorrect."
|
||||
);
|
||||
is(
|
||||
values[0].textContent,
|
||||
`"bar"`,
|
||||
"The first payload param value was incorrect."
|
||||
);
|
||||
is(
|
||||
labels[1].textContent,
|
||||
"baz",
|
||||
"The second payload param name was incorrect."
|
||||
);
|
||||
is(
|
||||
values[1].textContent,
|
||||
`"123"`,
|
||||
"The second payload param value was incorrect."
|
||||
);
|
||||
info("Switch to the Request panel");
|
||||
|
||||
wait = waitForDOM(document, "#request-panel .panel-container");
|
||||
clickOnSidebarTab(document, "request");
|
||||
await wait;
|
||||
|
||||
tabpanel = document.querySelector("#request-panel");
|
||||
if (expected.requestPanelFormData) {
|
||||
await waitUntil(
|
||||
() =>
|
||||
tabpanel.querySelector(".data-label").textContent ==
|
||||
L10N.getStr("paramsFormData")
|
||||
);
|
||||
|
||||
labels = tabpanel.querySelectorAll("tr .treeLabelCell .treeLabel");
|
||||
values = tabpanel.querySelectorAll("tr .treeValueCell .objectBox");
|
||||
|
||||
for (let i = 0; i < labels.length; i++) {
|
||||
is(
|
||||
labels[i].textContent,
|
||||
expected.requestPanelFormData[i].label,
|
||||
"The form data param name was incorrect."
|
||||
);
|
||||
is(
|
||||
values[i].textContent,
|
||||
expected.requestPanelFormData[i].value,
|
||||
"The form data param value was incorrect."
|
||||
);
|
||||
}
|
||||
|
||||
info("Toggle open the the request payload raw view");
|
||||
|
||||
tabpanel.querySelector("#raw-request-checkbox").click();
|
||||
}
|
||||
await waitUntil(
|
||||
() =>
|
||||
tabpanel.querySelector(".data-label").textContent ==
|
||||
L10N.getStr("paramsPostPayload") &&
|
||||
tabpanel.querySelector(
|
||||
".panel-container .editor-row-container .CodeMirror-code"
|
||||
)
|
||||
);
|
||||
|
||||
// Check that the expected header lines are included in the codemirror
|
||||
// text.
|
||||
const actualText = tabpanel.querySelector(
|
||||
".panel-container .editor-row-container .CodeMirror-code"
|
||||
).textContent;
|
||||
const requestPayloadIsCorrect = expected.requestPanelPayload.every(
|
||||
content => actualText.includes(content)
|
||||
);
|
||||
|
||||
is(requestPayloadIsCorrect, true, "The request payload is not correct");
|
||||
}
|
||||
|
||||
return teardown(monitor);
|
||||
});
|
||||
|
|
|
@ -41,7 +41,7 @@ add_task(async function() {
|
|||
const waitForPanel = waitForDOM(
|
||||
document,
|
||||
"#stack-trace-panel .frame-link",
|
||||
5
|
||||
6
|
||||
);
|
||||
// Open the stack-trace tab for that request
|
||||
document.getElementById("stack-trace-tab").click();
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
xhr.onreadystatechange = function() {
|
||||
if (this.readyState == this.DONE) {
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
};
|
||||
xhr.send(message);
|
||||
});
|
||||
|
|
|
@ -34,13 +34,32 @@
|
|||
|
||||
async function performRequests() {
|
||||
const rawData = [
|
||||
"content-type: application/x-www-form-urlencoded\r",
|
||||
"custom-header: hello world!\r",
|
||||
"\r",
|
||||
"\r",
|
||||
"foo=bar&baz=123",
|
||||
// Only one header
|
||||
[
|
||||
"content-type: application/x-www-form-urlencoded\r",
|
||||
"\r",
|
||||
"\r",
|
||||
"foo=bar&baz=123",
|
||||
],
|
||||
// No form body content
|
||||
[
|
||||
"content-type: application/x-www-form-urlencoded\r",
|
||||
"\r",
|
||||
"\r",
|
||||
],
|
||||
// Multiple headers
|
||||
[
|
||||
"content-type: application/x-www-form-urlencoded\r",
|
||||
"custom-header: hello world!\r",
|
||||
"\r",
|
||||
"\r",
|
||||
"foo=bar&baz=123",
|
||||
],
|
||||
];
|
||||
await post("sjs_simple-test-server.sjs", rawData.join("\n"));
|
||||
|
||||
for (const data of rawData) {
|
||||
await post("sjs_simple-test-server.sjs", data.join("\n"));
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
|
Загрузка…
Ссылка в новой задаче