Bug 1331730 - Log CORS messages from the content process r=bz,mayhemer

In e10s, a channel created by parent does not have a reliable reference
to the inner window ID that initiated the request. Without that, the
channel must request that the content process log and blocked messages
to the web console. This patch creates a new ipdl interface to pass the
message from the parent to the child process. The nsCORSListenerProxy
also needs to keep a reference to the nsIHttpChannel that created it so
it can find its way back to the child. Additionally, the
HttpChannelParent needs to be propagated when creating a new channel for
CORS.

MozReview-Commit-ID: 8CUhlVCTWxt

--HG--
extra : rebase_source : 350f39ad6f7ada39e88dfcc69c4f2c470e2be0de
This commit is contained in:
Kate McKinley 2017-02-15 12:40:41 +09:00
Родитель 4d5da90a53
Коммит 84d5adef43
18 изменённых файлов: 1688 добавлений и 60 удалений

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

@ -0,0 +1,8 @@
[DEFAULT]
support-files =
file_CrossSiteXHR_server.sjs
file_CrossSiteXHR_inner.html
file_cors_logging_test.html
head.js
[browser_CORS-console-warnings.js]

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

@ -0,0 +1,93 @@
/*
* Description of the test:
* Ensure that CORS warnings are printed to the web console.
*
* This test uses the same tests as the plain mochitest, but needs access to
* the console.
*/
'use strict';
function console_observer(subject, topic, data) {
var message = subject.wrappedJSObject.arguments[0];
ok(false, message);
};
var webconsole = null;
var messages_seen = 0;
var expected_messages = 50;
function on_new_message(event, new_messages) {
for (let message of new_messages) {
let elem = message.node;
let text = elem.textContent;
if (text.match('Cross-Origin Request Blocked:')) {
ok(true, "message is: " + text);
messages_seen++;
}
}
}
function do_cleanup() {
if (webconsole) {
webconsole.ui.off("new-messages", on_new_message);
}
yield unsetCookiePref();
}
/**
* Set e10s related preferences in the test environment.
* @return {Promise} promise that resolves when preferences are set.
*/
function setCookiePref() {
return new Promise(resolve =>
// accept all cookies so that the CORS requests will send the right cookies
SpecialPowers.pushPrefEnv({
set: [
["network.cookie.cookieBehavior", 0],
]
}, resolve));
}
/**
* Unset e10s related preferences in the test environment.
* @return {Promise} promise that resolves when preferences are unset.
*/
function unsetCookiePref() {
return new Promise(resolve => {
SpecialPowers.popPrefEnv(resolve);
});
}
//jscs:disable
add_task(function*() {
//jscs:enable
// A longer timeout is necessary for this test than the plain mochitests
// due to opening a new tab with the web console.
requestLongerTimeout(4);
registerCleanupFunction(do_cleanup);
yield setCookiePref();
let test_uri = "http://mochi.test:8888/browser/dom/security/test/cors/file_cors_logging_test.html";
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
let toolbox = yield openToolboxForTab(tab, "webconsole");
ok(toolbox, "Got toolbox");
let hud = toolbox.getCurrentPanel().hud;
ok(hud, "Got hud");
if (!webconsole) {
registerCleanupFunction(do_cleanup);
hud.ui.on("new-messages", on_new_message);
webconsole = hud;
}
BrowserTestUtils.loadURI(gBrowser, test_uri);
yield BrowserTestUtils.waitForLocationChange(gBrowser, test_uri+"#finished");
// Different OS combinations
ok(messages_seen > 0, "Saw " + messages_seen + " messages.");
yield BrowserTestUtils.removeTab(tab);
});

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

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

@ -0,0 +1,69 @@
'use strict';
var { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
function scopedCuImport(path) {
const scope = {};
Cu.import(path, scope);
return scope;
}
const {loader, require} = scopedCuImport("resource://devtools/shared/Loader.jsm");
const {TargetFactory} = require("devtools/client/framework/target");
const {Utils: WebConsoleUtils} =
require("devtools/client/webconsole/utils");
let { gDevTools } = require("devtools/client/framework/devtools");
loader.lazyGetter(this, "HUDService", () => require("devtools/client/webconsole/webconsole"));
loader.lazyGetter(this, "HUDService", () => require("devtools/client/webconsole/hudservice"));
let promise = require("promise");
/**
* Open the toolbox in a given tab.
* @param {XULNode} tab The tab the toolbox should be opened in.
* @param {String} toolId Optional. The ID of the tool to be selected.
* @param {String} hostType Optional. The type of toolbox host to be used.
* @return {Promise} Resolves with the toolbox, when it has been opened.
*/
var openToolboxForTab = Task.async(function* (tab, toolId, hostType) {
info("Opening the toolbox");
let toolbox;
let target = TargetFactory.forTab(tab);
yield target.makeRemote();
// Check if the toolbox is already loaded.
toolbox = gDevTools.getToolbox(target);
if (toolbox) {
if (!toolId || (toolId && toolbox.getPanel(toolId))) {
info("Toolbox is already opened");
return toolbox;
}
}
// If not, load it now.
toolbox = yield gDevTools.showToolbox(target, toolId, hostType);
// Make sure that the toolbox frame is focused.
yield new Promise(resolve => waitForFocus(resolve, toolbox.win));
info("Toolbox opened and focused");
return toolbox;
});
/**
* Find multiple messages in the output.
*
* @param object hud
* The web console.
* @param string text
* A substring that can be found in the message.
* @param selector [optional]
* The selector to use in finding the message.
*/
function findMessages(hud, text, selector = ".message") {
const messages = hud.ui.experimentalOutputNode.querySelectorAll(selector);
const elements = Array.prototype.filter.call(
messages,
(el) => el.textContent.includes(text)
);
return elements;
}

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

@ -28,6 +28,7 @@ MOCHITEST_CHROME_MANIFESTS += [
]
BROWSER_CHROME_MANIFESTS += [
'cors/browser.ini',
'csp/browser.ini',
'general/browser.ini',
'hsts/browser.ini',

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

@ -54,6 +54,7 @@
#include "nsSocketTransportService2.h"
#include "nsStreamUtils.h"
#include "nsThreadUtils.h"
#include "nsCORSListenerProxy.h"
#ifdef MOZ_TASK_TRACER
#include "GeckoTaskTracer.h"
@ -3598,5 +3599,22 @@ HttpChannelChild::ActorDestroy(ActorDestroyReason aWhy)
}
}
mozilla::ipc::IPCResult
HttpChannelChild::RecvLogBlockedCORSRequest(const nsString& aMessage)
{
Unused << LogBlockedCORSRequest(aMessage);
return IPC_OK();
}
NS_IMETHODIMP
HttpChannelChild::LogBlockedCORSRequest(const nsAString & aMessage)
{
if (mLoadInfo) {
uint64_t innerWindowID = mLoadInfo->GetInnerWindowID();
nsCORSListenerProxy::LogBlockedCORSRequest(innerWindowID, aMessage);
}
return NS_OK;
}
} // namespace net
} // namespace mozilla

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

@ -179,6 +179,9 @@ protected:
// Get event target for processing network events.
already_AddRefed<nsIEventTarget> GetNeckoTarget() override;
virtual mozilla::ipc::IPCResult RecvLogBlockedCORSRequest(const nsString& aMessage) override;
NS_IMETHOD LogBlockedCORSRequest(const nsAString & aMessage) override;
private:
// this section is for main-thread-only object
// all the references need to be proxy released on main thread.

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

@ -232,6 +232,12 @@ HttpChannelParent::CleanupBackgroundChannel()
return;
}
// The nsHttpChannel may have a reference to this parent, release it
// to avoid circular references.
if (mChannel) {
mChannel->SetWarningReporter(nullptr);
}
if (!mPromise.IsEmpty()) {
mRequest.DisconnectIfExists();
mPromise.Reject(NS_ERROR_FAILURE, __func__);
@ -805,6 +811,8 @@ HttpChannelParent::ConnectChannel(const uint32_t& registrarId, const bool& shoul
return true;
}
mChannel->SetWarningReporter(this);
nsCOMPtr<nsINetworkInterceptController> controller;
NS_QueryNotificationCallbacks(channel, controller);
RefPtr<HttpChannelParentListener> parentListener = do_QueryObject(controller);
@ -1544,6 +1552,8 @@ HttpChannelParent::OnStopRequest(nsIRequest *aRequest,
mChannel->GetCacheReadStart(&timing.cacheReadStart);
mChannel->GetCacheReadEnd(&timing.cacheReadEnd);
mChannel->SetWarningReporter(nullptr);
// Either IPC channel is closed or background channel
// is ready to send OnStopRequest.
MOZ_ASSERT(mIPCClosed || mBgParent);
@ -2227,5 +2237,15 @@ HttpChannelParent::DoSendSetPriority(int16_t aValue)
}
}
nsresult
HttpChannelParent::LogBlockedCORSRequest(const nsAString& aMessage)
{
if (mIPCClosed ||
NS_WARN_IF(!SendLogBlockedCORSRequest(nsString(aMessage)))) {
return NS_ERROR_UNEXPECTED;
}
return NS_OK;
}
} // namespace net
} // namespace mozilla

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

@ -214,6 +214,7 @@ protected:
MOZ_MUST_USE nsresult
ReportSecurityMessage(const nsAString& aMessageTag,
const nsAString& aMessageCategory) override;
nsresult LogBlockedCORSRequest(const nsAString& aMessage) override;
// Calls SendDeleteSelf and sets mIPCClosed to true because we should not
// send any more messages after that. Bug 1274886

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

@ -854,6 +854,12 @@ NullHttpChannel::SetIsMainDocumentChannel(bool aValue)
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
NullHttpChannel::LogBlockedCORSRequest(const nsAString& aMessage)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
#define IMPL_TIMING_ATTR(name) \
NS_IMETHODIMP \
NullHttpChannel::Get##name##Time(PRTime* _retval) { \

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

@ -141,6 +141,11 @@ child:
// Tell the child to issue a deprecation warning.
async IssueDeprecationWarning(uint32_t warning, bool asError);
// When CORS blocks the request in the parent process, it doesn't have the
// correct window ID, so send the message to the child for logging to the web
// console.
async LogBlockedCORSRequest(nsString message);
both:
// After receiving this message, the parent also calls
// SendFinishInterceptedRedirect, and makes sure not to send any more messages

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

@ -42,8 +42,10 @@
#include "NullPrincipal.h"
#include "nsICorsPreflightCallback.h"
#include "nsISupportsImpl.h"
#include "nsHttpChannel.h"
#include "mozilla/LoadInfo.h"
#include "nsIHttpHeaderVisitor.h"
#include "nsQueryObject.h"
#include <algorithm>
using namespace mozilla;
@ -56,24 +58,11 @@ static bool gDisableCORSPrivateData = false;
static void
LogBlockedRequest(nsIRequest* aRequest,
const char* aProperty,
const char16_t* aParam)
const char16_t* aParam,
nsIHttpChannel* aCreatingChannel)
{
nsresult rv = NS_OK;
// Build the error object and log it to the console
nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv));
if (NS_FAILED(rv)) {
NS_WARNING("Failed to log blocked cross-site request (no console)");
return;
}
nsCOMPtr<nsIScriptError> scriptError =
do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to log blocked cross-site request (no scriptError)");
return;
}
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
nsCOMPtr<nsIURI> aUri;
channel->GetURI(getter_AddRefs(aUri));
@ -98,34 +87,19 @@ LogBlockedRequest(nsIRequest* aRequest,
nsAutoString msg(blockedMessage.get());
// query innerWindowID and log to web console, otherwise log to
// the error to the browser console.
uint64_t innerWindowID = nsContentUtils::GetInnerWindowID(aRequest);
if (XRE_IsParentProcess()) {
if (aCreatingChannel) {
rv = aCreatingChannel->LogBlockedCORSRequest(msg);
if (NS_SUCCEEDED(rv)) {
return;
}
}
NS_WARNING("Failed to log blocked cross-site request to web console from parent->child, falling back to browser console");
}
if (innerWindowID > 0) {
rv = scriptError->InitWithWindowID(msg,
EmptyString(), // sourceName
EmptyString(), // sourceLine
0, // lineNumber
0, // columnNumber
nsIScriptError::warningFlag,
"CORS",
innerWindowID);
}
else {
rv = scriptError->Init(msg,
EmptyString(), // sourceName
EmptyString(), // sourceLine
0, // lineNumber
0, // columnNumber
nsIScriptError::warningFlag,
"CORS");
}
if (NS_FAILED(rv)) {
NS_WARNING("Failed to log blocked cross-site request (scriptError init failed)");
return;
}
console->LogMessage(scriptError);
// log message ourselves
uint64_t innerWindowID = nsContentUtils::GetInnerWindowID(aRequest);
nsCORSListenerProxy::LogBlockedCORSRequest(innerWindowID, msg);
}
//////////////////////////////////////////////////////////////////////////
@ -451,6 +425,7 @@ nsCORSListenerProxy::Init(nsIChannel* aChannel, DataURIHandling aAllowDataURI)
mRequestingPrincipal = nullptr;
mOriginHeaderPrincipal = nullptr;
mOuterNotificationCallbacks = nullptr;
mHttpChannel = nullptr;
}
#ifdef DEBUG
mInited = true;
@ -540,9 +515,11 @@ nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest)
if (!mHasBeenCrossSite) {
return NS_OK;
}
nsCOMPtr<nsIHttpChannel> topChannel;
topChannel.swap(mHttpChannel);
if (gDisableCORS) {
LogBlockedRequest(aRequest, "CORSDisabled", nullptr);
LogBlockedRequest(aRequest, "CORSDisabled", nullptr, topChannel);
return NS_ERROR_DOM_BAD_URI;
}
@ -560,7 +537,7 @@ nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest)
// Test that things worked on a HTTP level
nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(aRequest);
if (!http) {
LogBlockedRequest(aRequest, "CORSRequestNotHttp", nullptr);
LogBlockedRequest(aRequest, "CORSRequestNotHttp", nullptr, topChannel);
return NS_ERROR_DOM_BAD_URI;
}
@ -582,14 +559,14 @@ nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest)
// check for duplicate headers
rv = http->VisitOriginalResponseHeaders(visitor);
if (NS_FAILED(rv)) {
LogBlockedRequest(aRequest, "CORSAllowOriginNotMatchingOrigin", nullptr);
LogBlockedRequest(aRequest, "CORSAllowOriginNotMatchingOrigin", nullptr, topChannel);
return rv;
}
rv = http->GetResponseHeader(
NS_LITERAL_CSTRING("Access-Control-Allow-Origin"), allowedOriginHeader);
if (NS_FAILED(rv)) {
LogBlockedRequest(aRequest, "CORSMissingAllowOrigin", nullptr);
LogBlockedRequest(aRequest, "CORSMissingAllowOrigin", nullptr, topChannel);
return rv;
}
@ -602,7 +579,7 @@ nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest)
// below since "if (A && B)" is included in "if (A || !B)".
//
if (mWithCredentials && allowedOriginHeader.EqualsLiteral("*")) {
LogBlockedRequest(aRequest, "CORSNotSupportingCredentials", nullptr);
LogBlockedRequest(aRequest, "CORSNotSupportingCredentials", nullptr, topChannel);
return NS_ERROR_DOM_BAD_URI;
}
@ -613,7 +590,7 @@ nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest)
if (!allowedOriginHeader.Equals(origin)) {
LogBlockedRequest(aRequest, "CORSAllowOriginNotMatchingOrigin",
NS_ConvertUTF8toUTF16(allowedOriginHeader).get());
NS_ConvertUTF8toUTF16(allowedOriginHeader).get(), topChannel);
return NS_ERROR_DOM_BAD_URI;
}
}
@ -625,7 +602,7 @@ nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest)
NS_LITERAL_CSTRING("Access-Control-Allow-Credentials"), allowCredentialsHeader);
if (!allowCredentialsHeader.EqualsLiteral("true")) {
LogBlockedRequest(aRequest, "CORSMissingAllowCredentials", nullptr);
LogBlockedRequest(aRequest, "CORSMissingAllowCredentials", nullptr, topChannel);
return NS_ERROR_DOM_BAD_URI;
}
}
@ -642,6 +619,7 @@ nsCORSListenerProxy::OnStopRequest(nsIRequest* aRequest,
nsresult rv = mOuterListener->OnStopRequest(aRequest, aContext, aStatusCode);
mOuterListener = nullptr;
mOuterNotificationCallbacks = nullptr;
mHttpChannel = nullptr;
return rv;
}
@ -994,6 +972,8 @@ nsCORSListenerProxy::UpdateChannel(nsIChannel* aChannel,
NS_ENSURE_SUCCESS(rv, rv);
}
mHttpChannel = http;
return NS_OK;
}
@ -1310,11 +1290,12 @@ nsCORSPreflightListener::CheckPreflightRequestApproved(nsIRequest* aRequest)
nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(aRequest);
nsCOMPtr<nsIHttpChannelInternal> internal = do_QueryInterface(aRequest);
NS_ENSURE_STATE(internal);
nsCOMPtr<nsIHttpChannel> parentHttpChannel = do_QueryInterface(mCallback);
bool succeedded;
rv = http->GetRequestSucceeded(&succeedded);
if (NS_FAILED(rv) || !succeedded) {
LogBlockedRequest(aRequest, "CORSPreflightDidNotSucceed", nullptr);
LogBlockedRequest(aRequest, "CORSPreflightDidNotSucceed", nullptr, parentHttpChannel);
return NS_ERROR_DOM_BAD_URI;
}
@ -1334,13 +1315,13 @@ nsCORSPreflightListener::CheckPreflightRequestApproved(nsIRequest* aRequest)
}
if (!NS_IsValidHTTPToken(method)) {
LogBlockedRequest(aRequest, "CORSInvalidAllowMethod",
NS_ConvertUTF8toUTF16(method).get());
NS_ConvertUTF8toUTF16(method).get(), parentHttpChannel);
return NS_ERROR_DOM_BAD_URI;
}
foundMethod |= mPreflightMethod.Equals(method);
}
if (!foundMethod) {
LogBlockedRequest(aRequest, "CORSMethodNotFound", nullptr);
LogBlockedRequest(aRequest, "CORSMethodNotFound", nullptr, parentHttpChannel);
return NS_ERROR_DOM_BAD_URI;
}
@ -1357,7 +1338,7 @@ nsCORSPreflightListener::CheckPreflightRequestApproved(nsIRequest* aRequest)
}
if (!NS_IsValidHTTPToken(header)) {
LogBlockedRequest(aRequest, "CORSInvalidAllowHeader",
NS_ConvertUTF8toUTF16(header).get());
NS_ConvertUTF8toUTF16(header).get(), parentHttpChannel);
return NS_ERROR_DOM_BAD_URI;
}
headers.AppendElement(header);
@ -1366,7 +1347,7 @@ nsCORSPreflightListener::CheckPreflightRequestApproved(nsIRequest* aRequest)
if (!headers.Contains(mPreflightHeaders[i],
nsCaseInsensitiveCStringArrayComparator())) {
LogBlockedRequest(aRequest, "CORSMissingAllowHeaderFromPreflight",
NS_ConvertUTF8toUTF16(mPreflightHeaders[i]).get());
NS_ConvertUTF8toUTF16(mPreflightHeaders[i]).get(), parentHttpChannel);
return NS_ERROR_DOM_BAD_URI;
}
}
@ -1396,6 +1377,7 @@ nsCORSListenerProxy::RemoveFromCorsPreflightCache(nsIURI* aURI,
}
}
// static
nsresult
nsCORSListenerProxy::StartCORSPreflight(nsIChannel* aRequestChannel,
nsICorsPreflightCallback* aCallback,
@ -1405,7 +1387,8 @@ nsCORSListenerProxy::StartCORSPreflight(nsIChannel* aRequestChannel,
*aPreflightChannel = nullptr;
if (gDisableCORS) {
LogBlockedRequest(aRequestChannel, "CORSDisabled", nullptr);
nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(aRequestChannel);
LogBlockedRequest(aRequestChannel, "CORSDisabled", nullptr, http);
return NS_ERROR_DOM_BAD_URI;
}
@ -1501,6 +1484,13 @@ nsCORSListenerProxy::StartCORSPreflight(nsIChannel* aRequestChannel,
method, false);
NS_ENSURE_SUCCESS(rv, rv);
// Set the CORS preflight channel's warning reporter to be the same as the
// requesting channel so that all log messages are able to be reported through
// the warning reporter.
RefPtr<nsHttpChannel> reqCh = do_QueryObject(aRequestChannel);
RefPtr<nsHttpChannel> preCh = do_QueryObject(preHttp);
preCh->SetWarningReporter(reqCh->GetWarningReporter());
nsTArray<nsCString> preflightHeaders;
if (!aUnsafeHeaders.IsEmpty()) {
for (uint32_t i = 0; i < aUnsafeHeaders.Length(); ++i) {
@ -1538,3 +1528,52 @@ nsCORSListenerProxy::StartCORSPreflight(nsIChannel* aRequestChannel,
return NS_OK;
}
// static
void
nsCORSListenerProxy::LogBlockedCORSRequest(uint64_t aInnerWindowID,
const nsAString& aMessage)
{
nsresult rv = NS_OK;
// Build the error object and log it to the console
nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv));
if (NS_FAILED(rv)) {
NS_WARNING("Failed to log blocked cross-site request (no console)");
return;
}
nsCOMPtr<nsIScriptError> scriptError =
do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to log blocked cross-site request (no scriptError)");
return;
}
// query innerWindowID and log to web console, otherwise log to
// the error to the browser console.
if (aInnerWindowID > 0) {
rv = scriptError->InitWithWindowID(aMessage,
EmptyString(), // sourceName
EmptyString(), // sourceLine
0, // lineNumber
0, // columnNumber
nsIScriptError::warningFlag,
"CORS",
aInnerWindowID);
}
else {
rv = scriptError->Init(aMessage,
EmptyString(), // sourceName
EmptyString(), // sourceLine
0, // lineNumber
0, // columnNumber
nsIScriptError::warningFlag,
"CORS");
}
if (NS_FAILED(rv)) {
NS_WARNING("Failed to log blocked cross-site request (scriptError init failed)");
return;
}
console->LogMessage(scriptError);
}

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

@ -70,6 +70,10 @@ public:
void SetInterceptController(nsINetworkInterceptController* aInterceptController);
// When CORS blocks a request, log the message to the web console, or the
// browser console if no valid inner window ID is found.
static void LogBlockedCORSRequest(uint64_t aInnerWindowID,
const nsAString& aMessage);
private:
// Only HttpChannelParent can call RemoveFromCorsPreflightCache
friend class mozilla::net::HttpChannelParent;
@ -108,6 +112,10 @@ private:
// an http: request to https: in nsHttpChannel::Connect() and hence
// a request might not be marked as cross site request based on that promise.
bool mHasBeenCrossSite;
// Under e10s, logging happens in the child process. Keep a reference to the
// creator nsIHttpChannel in order to find the way back to the child. Released
// in OnStopRequest().
nsCOMPtr<nsIHttpChannel> mHttpChannel;
#ifdef DEBUG
bool mInited;
#endif

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

@ -416,6 +416,15 @@ nsHttpChannel::AddSecurityMessage(const nsAString& aMessageTag,
aMessageCategory);
}
NS_IMETHODIMP
nsHttpChannel::LogBlockedCORSRequest(const nsAString& aMessage)
{
if (mWarningReporter) {
return mWarningReporter->LogBlockedCORSRequest(aMessage);
}
return NS_ERROR_UNEXPECTED;
}
//-----------------------------------------------------------------------------
// nsHttpChannel <private>
//-----------------------------------------------------------------------------
@ -858,6 +867,7 @@ nsHttpChannel::ReleaseListeners()
{
HttpBaseChannel::ReleaseListeners();
mChannelClassifier = nullptr;
mWarningReporter = nullptr;
}
void
@ -5922,6 +5932,7 @@ nsHttpChannel::Cancel(nsresult status)
LOG((" ignoring; already canceled\n"));
return NS_OK;
}
if (mWaitingForRedirectCallback) {
LOG(("channel canceled during wait for redirect callback"));
}
@ -9250,5 +9261,19 @@ nsHttpChannel::Notify(nsITimer *aTimer)
return NS_OK;
}
void
nsHttpChannel::SetWarningReporter(HttpChannelSecurityWarningReporter *aReporter)
{
LOG(("nsHttpChannel [this=%p] SetWarningReporter [%p]", this, aReporter));
mWarningReporter = aReporter;
}
HttpChannelSecurityWarningReporter*
nsHttpChannel::GetWarningReporter()
{
LOG(("nsHttpChannel [this=%p] GetWarningReporter [%p]", this, mWarningReporter.get()));
return mWarningReporter.get();
}
} // namespace net
} // namespace mozilla

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

@ -43,12 +43,13 @@ namespace mozilla { namespace net {
class nsChannelClassifier;
class Http2PushedStream;
class HttpChannelSecurityWarningReporter
class HttpChannelSecurityWarningReporter : public nsISupports
{
public:
virtual MOZ_MUST_USE nsresult
ReportSecurityMessage(const nsAString& aMessageTag,
const nsAString& aMessageCategory) = 0;
virtual nsresult LogBlockedCORSRequest(const nsAString& aMessage) = 0;
};
//-----------------------------------------------------------------------------
@ -190,10 +191,10 @@ public:
MOZ_MUST_USE nsresult
AddSecurityMessage(const nsAString& aMessageTag,
const nsAString& aMessageCategory) override;
NS_IMETHOD LogBlockedCORSRequest(const nsAString& aMessage) override;
void SetWarningReporter(HttpChannelSecurityWarningReporter* aReporter)
{ mWarningReporter = aReporter; }
void SetWarningReporter(HttpChannelSecurityWarningReporter *aReporter);
HttpChannelSecurityWarningReporter* GetWarningReporter();
public: /* internal necko use only */
using InitLocalBlockListCallback = std::function<void(bool)>;
@ -672,7 +673,7 @@ private:
nsCString mUsername;
// If non-null, warnings should be reported to this object.
HttpChannelSecurityWarningReporter* mWarningReporter;
RefPtr<HttpChannelSecurityWarningReporter> mWarningReporter;
RefPtr<ADivertableParentChannel> mParentChannel;

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

@ -478,4 +478,14 @@ interface nsIHttpChannel : nsIChannel
* Don't alter it otherwise.
*/
[must_use] attribute uint64_t topLevelOuterContentWindowId;
/**
* In e10s, the information that the CORS response blocks the load is in the
* parent, which doesn't know the true window id of the request, so we may
* need to proxy the request to the child.
*
* @param aMessage
* The message to print in the console.
*/
void logBlockedCORSRequest(in AString aMessage);
};

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

@ -1044,3 +1044,13 @@ nsViewSourceChannel::SetCorsPreflightParameters(const nsTArray<nsCString>& aUnsa
{
mHttpChannelInternal->SetCorsPreflightParameters(aUnsafeHeaders);
}
NS_IMETHODIMP
nsViewSourceChannel::LogBlockedCORSRequest(const nsAString& aMessage)
{
if (!mHttpChannel) {
NS_WARNING("nsViewSourceChannel::LogBlockedCORSRequest mHttpChannel is null");
return NS_ERROR_UNEXPECTED;
}
return mHttpChannel->LogBlockedCORSRequest(aMessage);
}