зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
317f664881
Коммит
c7d31b32e2
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче