Bug 1270096 - Netmonitor request replay: disable CORS checks, set request headers accurately r=Honza

MozReview-Commit-ID: Ew7zPkrhOHd

--HG--
extra : rebase_source : 876fa547e3f26d35c6798c4c8f1f5011998bd55b
This commit is contained in:
Jarda Snajdr 2016-05-23 15:27:45 +02:00
Родитель 317f664881
Коммит c7d31b32e2
5 изменённых файлов: 193 добавлений и 11 удалений

Просмотреть файл

@ -114,6 +114,8 @@ skip-if = (os == 'linux' && e10s && debug) # Bug 1242204
[browser_net_reload-button.js]
[browser_net_reload-markers.js]
[browser_net_req-resp-bodies.js]
[browser_net_resend_cors.js]
[browser_net_resend_headers.js]
[browser_net_resend.js]
[browser_net_security-details.js]
[browser_net_security-error.js]

Просмотреть файл

@ -9,6 +9,7 @@
const ADD_QUERY = "t1=t2";
const ADD_HEADER = "Test-header: true";
const ADD_UA_HEADER = "User-Agent: Custom-Agent";
const ADD_POSTDATA = "&t3=t4";
add_task(function* () {
@ -129,6 +130,11 @@ add_task(function* () {
type(["VK_RETURN"]);
type(ADD_HEADER);
// add a User-Agent header, to check if default headers can be modified
// (there will be two of them, first gets overwritten by the second)
type(["VK_RETURN"]);
type(ADD_UA_HEADER);
let postData = document.getElementById("custom-postdata-value");
let postFocus = once(postData, "focus", false);
postData.focus();
@ -149,6 +155,9 @@ add_task(function* () {
let hasHeader = headers.some(h => `${h.name}: ${h.value}` == ADD_HEADER);
ok(hasHeader, "new header added to sent request");
let hasUAHeader = headers.some(h => `${h.name}: ${h.value}` == ADD_UA_HEADER);
ok(hasUAHeader, "User-Agent header added to sent request");
is(data.requestPostData.postData.text,
origData.requestPostData.postData.text + ADD_POSTDATA,
"post data added to sent request");

Просмотреть файл

@ -0,0 +1,80 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/**
* Tests if resending a CORS request avoids the security checks and doesn't send
* a preflight OPTIONS request (bug 1270096 and friends)
*/
add_task(function* () {
let { tab, monitor } = yield initNetMonitor(CORS_URL);
info("Starting test... ");
let { EVENTS, NetMonitorView } = monitor.panelWin;
let { RequestsMenu } = NetMonitorView;
RequestsMenu.lazyUpdate = false;
let requestUrl = "http://test1.example.com" + CORS_SJS_PATH;
info("Waiting for OPTIONS, then POST");
let wait = waitForNetworkEvents(monitor, 1, 1);
yield ContentTask.spawn(tab.linkedBrowser, requestUrl, function* (url) {
content.wrappedJSObject.performRequests(url, "triggering/preflight", "post-data");
});
yield wait;
const METHODS = ["OPTIONS", "POST"];
// Check the requests that were sent
for (let [i, method] of METHODS.entries()) {
let { attachment } = RequestsMenu.getItemAtIndex(i);
is(attachment.method, method, `The ${method} request has the right method`);
is(attachment.url, requestUrl, `The ${method} request has the right URL`);
}
// Resend both requests without modification. Wait for resent OPTIONS, then POST.
// POST is supposed to have no preflight OPTIONS request this time (CORS is disabled)
let onRequests = waitForNetworkEvents(monitor, 1, 1);
for (let [i, method] of METHODS.entries()) {
let item = RequestsMenu.getItemAtIndex(i);
info(`Selecting the ${method} request (at index ${i})`);
let onUpdate = monitor.panelWin.once(EVENTS.TAB_UPDATED);
RequestsMenu.selectedItem = item;
yield onUpdate;
info("Cloning the selected request into a custom clone");
let onPopulate = monitor.panelWin.once(EVENTS.CUSTOMREQUESTVIEW_POPULATED);
RequestsMenu.cloneSelectedRequest();
yield onPopulate;
info("Sending the cloned request (without change)");
RequestsMenu.sendCustomRequest();
}
info("Waiting for both resent requests");
yield onRequests;
// Check the resent requests
for (let [i, method] of METHODS.entries()) {
let index = i + 2;
let item = RequestsMenu.getItemAtIndex(index).attachment;
is(item.method, method, `The ${method} request has the right method`);
is(item.url, requestUrl, `The ${method} request has the right URL`);
is(item.status, 200, `The ${method} response has the right status`);
if (method === "POST") {
is(item.requestPostData.postData.text, "post-data",
"The POST request has the right POST data");
// eslint-disable-next-line mozilla/no-cpows-in-tests
is(item.responseContent.content.text, "Access-Control-Allow-Origin: *",
"The POST response has the right content");
}
}
info("Finishing the test");
return teardown(monitor);
});

Просмотреть файл

@ -0,0 +1,67 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/**
* Test if custom request headers are not ignored (bug 1270096 and friends)
*/
add_task(function* () {
let { monitor } = yield initNetMonitor(SIMPLE_SJS);
info("Starting test... ");
let { NetMonitorView, NetMonitorController } = monitor.panelWin;
let { RequestsMenu } = NetMonitorView;
RequestsMenu.lazyUpdate = false;
let requestUrl = SIMPLE_SJS;
let requestHeaders = [
{ name: "Host", value: "fakehost.example.com" },
{ name: "User-Agent", value: "Testzilla" },
{ name: "Referer", value: "http://example.com/referrer" },
{ name: "Accept", value: "application/jarda"},
{ name: "Accept-Encoding", value: "compress, identity, funcoding" },
{ name: "Accept-Language", value: "cs-CZ" }
];
let wait = waitForNetworkEvents(monitor, 0, 1);
NetMonitorController.webConsoleClient.sendHTTPRequest({
url: requestUrl,
method: "POST",
headers: requestHeaders,
body: "Hello"
});
yield wait;
let { attachment } = RequestsMenu.getItemAtIndex(0);
is(attachment.method, "POST", "The request has the right method");
is(attachment.url, requestUrl, "The request has the right URL");
for (let { name, value } of attachment.requestHeaders.headers) {
info(`Request header: ${name}: ${value}`);
}
function hasRequestHeader(name, value) {
let { headers } = attachment.requestHeaders;
return headers.some(h => h.name === name && h.value === value);
}
function hasNotRequestHeader(name) {
let { headers } = attachment.requestHeaders;
return headers.every(h => h.name !== name);
}
for (let { name, value } of requestHeaders) {
ok(hasRequestHeader(name, value), `The ${name} header has the right value`);
}
// Check that the Cookie header was not added silently (i.e., that the request is
// anonymous.
for (let name of ["Cookie"]) {
ok(hasNotRequestHeader(name), `The ${name} header is not present`);
}
return teardown(monitor);
});

Просмотреть файл

@ -23,6 +23,7 @@ loader.lazyRequireGetter(this, "events", "sdk/event/core");
loader.lazyRequireGetter(this, "ServerLoggingListener", "devtools/shared/webconsole/server-logger", true);
loader.lazyRequireGetter(this, "JSPropertyProvider", "devtools/shared/webconsole/js-property-provider", true);
loader.lazyRequireGetter(this, "Parser", "resource://devtools/shared/Parser.jsm", true);
loader.lazyRequireGetter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm", true);
for (let name of ["WebConsoleUtils", "ConsoleServiceListener",
"ConsoleAPIListener", "addWebConsoleCommands",
@ -1563,23 +1564,46 @@ WebConsoleActor.prototype =
/**
* Send a new HTTP request from the target's window.
*
* @param object aMessage
* @param object message
* Object with 'request' - the HTTP request details.
*/
onSendHTTPRequest: function WCA_onSendHTTPRequest(aMessage)
{
let details = aMessage.request;
onSendHTTPRequest(message) {
let { url, method, headers, body } = message.request;
// send request from target's window
let request = new this.window.XMLHttpRequest();
request.open(details.method, details.url, true);
// Set the loadingNode and loadGroup to the target document - otherwise the
// request won't show up in the opened netmonitor.
let doc = this.window.document;
for (let {name, value} of details.headers) {
request.setRequestHeader(name, value);
let channel = NetUtil.newChannel({
uri: NetUtil.newURI(url),
loadingNode: doc,
securityFlags: Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER
});
channel.QueryInterface(Ci.nsIHttpChannel);
channel.loadGroup = doc.documentLoadGroup;
channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE |
Ci.nsIRequest.INHIBIT_CACHING |
Ci.nsIRequest.LOAD_ANONYMOUS;
channel.requestMethod = method;
for (let {name, value} of headers) {
channel.setRequestHeader(name, value, false);
}
request.send(details.body);
let channel = request.channel.QueryInterface(Ci.nsIHttpChannel);
if (body) {
channel.QueryInterface(Ci.nsIUploadChannel2);
let bodyStream = Cc["@mozilla.org/io/string-input-stream;1"]
.createInstance(Ci.nsIStringInputStream);
bodyStream.setData(body, body.length);
channel.explicitSetUploadStream(bodyStream, null, -1, method, false);
}
NetUtil.asyncFetch(channel, () => {});
let actor = this.getNetworkEventActor(channel.channelId);
// map channel to actor so we can associate future events with it