Bug 1121824 - Improve CORS console messages when request is blocked (r=sicking)

This commit is contained in:
Christoph Kerschbaumer 2015-01-22 17:20:58 -08:00
parent 92e95883b2
commit 2febb6d0f8
2 changed files with 94 additions and 41 deletions

View File

@ -4,7 +4,18 @@ BlockMixedDisplayContent = Blocked loading mixed display content "%1$S"
BlockMixedActiveContent = Blocked loading mixed active content "%1$S"
# CORS
CrossSiteRequestBlocked=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. This can be fixed by moving the resource to the same domain or enabling CORS.
# LOCALIZATION NOTE: Do not translate "Access-Control-Allow-Origin", Access-Control-Allow-Credentials, Access-Control-Allow-Methods, Access-Control-Allow-Headers
CORSDisabled=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: CORS disabled).
CORSRequestFailed=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: CORS request failed).
CORSRequestNotHttp=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: CORS request not http).
CORSMissingAllowOrigin=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: CORS header 'Access-Control-Allow-Origin' missing).
CORSAllowOriginNotMatchingOrigin=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: CORS header 'Access-Control-Allow-Origin' does not match '%2$S').
CORSMethodNotFound=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: Did not find method in CORS header 'Access-Control-Allow-Methods').
CORSMissingAllowCredentials=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: expected 'true' in CORS header 'Access-Control-Allow-Credentials').
CORSPreflightDidNotSucceed=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: CORS preflight channel did not succeed).
CORSInvalidAllowMethod=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: invalid token '%2$S' in CORS header 'Access-Control-Allow-Methods').
CORSInvalidAllowHeader=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: invalid token '%2$S' in CORS header 'Access-Control-Allow-Headers').
CORSMissingAllowHeaderFromPreflight=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: missing token '%2$S' in CORS header 'Access-Control-Allow-Headers' from CORS preflight channel"));
# LOCALIZATION NOTE: Do not translate "Strict-Transport-Security" or "HSTS"
InvalidSTSHeaders=The site specified an invalid Strict-Transport-Security header.

View File

@ -42,16 +42,25 @@ using namespace mozilla;
static bool gDisableCORS = false;
static bool gDisableCORSPrivateData = false;
static nsresult
LogBlockedRequest(nsIRequest* aRequest)
static void
LogBlockedRequest(nsIRequest* aRequest,
const char* aProperty,
const char16_t* aParam)
{
nsresult rv = NS_OK;
// Get the innerWindowID associated with the XMLHTTPRequest
uint64_t innerWindowID = nsContentUtils::GetInnerWindowID(aRequest);
// 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;
}
if (!innerWindowID) {
return NS_ERROR_FAILURE;
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);
@ -65,32 +74,47 @@ LogBlockedRequest(nsIRequest* aRequest)
// Generate the error message
nsXPIDLString blockedMessage;
NS_ConvertUTF8toUTF16 specUTF16(spec);
const char16_t* params[] = { specUTF16.get() };
const char16_t* params[] = { specUTF16.get(), aParam };
rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eSECURITY_PROPERTIES,
"CrossSiteRequestBlocked",
aProperty,
params,
blockedMessage);
// Build the error object and log it to the console
nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIScriptError> scriptError = do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to log blocked cross-site request (no formalizedStr");
return;
}
nsAutoString msg(blockedMessage.get());
rv = scriptError->InitWithWindowID(msg,
NS_ConvertUTF8toUTF16(spec),
EmptyString(),
0,
0,
nsIScriptError::warningFlag,
"CORS",
innerWindowID);
NS_ENSURE_SUCCESS(rv, rv);
rv = console->LogMessage(scriptError);
return rv;
// query innerWindowID and log to web console, otherwise log to
// the error to the browser console.
uint64_t innerWindowID = nsContentUtils::GetInnerWindowID(aRequest);
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);
}
//////////////////////////////////////////////////////////////////////////
@ -470,8 +494,6 @@ nsCORSListenerProxy::OnStartRequest(nsIRequest* aRequest,
nsresult rv = CheckRequestApproved(aRequest);
mRequestApproved = NS_SUCCEEDED(rv);
if (!mRequestApproved) {
rv = LogBlockedRequest(aRequest);
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to log blocked cross-site request");
if (sPreflightCache) {
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
if (channel) {
@ -503,31 +525,45 @@ nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest)
}
if (gDisableCORS) {
LogBlockedRequest(aRequest, "CORSDisabled", nullptr);
return NS_ERROR_DOM_BAD_URI;
}
// Check if the request failed
nsresult status;
nsresult rv = aRequest->GetStatus(&status);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_SUCCESS(status, status);
if (NS_FAILED(rv)) {
LogBlockedRequest(aRequest, "CORSRequestFailed", nullptr);
return rv;
}
if (NS_FAILED(status)) {
LogBlockedRequest(aRequest, "CORSRequestFailed", nullptr);
return status;
}
// Test that things worked on a HTTP level
nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(aRequest);
NS_ENSURE_TRUE(http, NS_ERROR_DOM_BAD_URI);
if (!http) {
LogBlockedRequest(aRequest, "CORSRequestNotHttp", nullptr);
return NS_ERROR_DOM_BAD_URI;
}
// Check the Access-Control-Allow-Origin header
nsAutoCString allowedOriginHeader;
rv = http->GetResponseHeader(
NS_LITERAL_CSTRING("Access-Control-Allow-Origin"), allowedOriginHeader);
NS_ENSURE_SUCCESS(rv, rv);
if (NS_FAILED(rv)) {
LogBlockedRequest(aRequest, "CORSMissingAllowOrigin", nullptr);
return rv;
}
if (mWithCredentials || !allowedOriginHeader.EqualsLiteral("*")) {
nsAutoCString origin;
rv = nsContentUtils::GetASCIIOrigin(mOriginHeaderPrincipal, origin);
NS_ENSURE_SUCCESS(rv, rv);
nsContentUtils::GetASCIIOrigin(mOriginHeaderPrincipal, origin);
if (!allowedOriginHeader.Equals(origin)) {
LogBlockedRequest(aRequest, "CORSAllowOriginNotMatchingOrigin",
NS_ConvertUTF8toUTF16(allowedOriginHeader).get());
return NS_ERROR_DOM_BAD_URI;
}
}
@ -537,9 +573,9 @@ nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest)
nsAutoCString allowCredentialsHeader;
rv = http->GetResponseHeader(
NS_LITERAL_CSTRING("Access-Control-Allow-Credentials"), allowCredentialsHeader);
NS_ENSURE_SUCCESS(rv, rv);
if (!allowCredentialsHeader.EqualsLiteral("true")) {
LogBlockedRequest(aRequest, "CORSMissingAllowCredentials", nullptr);
return NS_ERROR_DOM_BAD_URI;
}
}
@ -547,8 +583,8 @@ nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest)
if (mIsPreflight) {
bool succeedded;
rv = http->GetRequestSucceeded(&succeedded);
NS_ENSURE_SUCCESS(rv, rv);
if (!succeedded) {
if (NS_FAILED(rv) || !succeedded) {
LogBlockedRequest(aRequest, "CORSPreflightDidNotSucceed", nullptr);
return NS_ERROR_DOM_BAD_URI;
}
@ -567,11 +603,16 @@ nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest)
continue;
}
if (!NS_IsValidHTTPToken(method)) {
LogBlockedRequest(aRequest, "CORSInvalidAllowMethod",
NS_ConvertUTF8toUTF16(method).get());
return NS_ERROR_DOM_BAD_URI;
}
foundMethod |= mPreflightMethod.Equals(method);
}
NS_ENSURE_TRUE(foundMethod, NS_ERROR_DOM_BAD_URI);
if (!foundMethod) {
LogBlockedRequest(aRequest, "CORSMethodNotFound", nullptr);
return NS_ERROR_DOM_BAD_URI;
}
// The "Access-Control-Allow-Headers" header contains a comma separated
// list of header names.
@ -586,6 +627,8 @@ nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest)
continue;
}
if (!NS_IsValidHTTPToken(header)) {
LogBlockedRequest(aRequest, "CORSInvalidAllowHeader",
NS_ConvertUTF8toUTF16(header).get());
return NS_ERROR_DOM_BAD_URI;
}
headers.AppendElement(header);
@ -593,6 +636,8 @@ nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest)
for (uint32_t i = 0; i < mPreflightHeaders.Length(); ++i) {
if (!headers.Contains(mPreflightHeaders[i],
nsCaseInsensitiveCStringArrayComparator())) {
LogBlockedRequest(aRequest, "CORSMissingAllowHeaderFromPreflight",
NS_ConvertUTF8toUTF16(mPreflightHeaders[i]).get());
return NS_ERROR_DOM_BAD_URI;
}
}
@ -656,9 +701,6 @@ nsCORSListenerProxy::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
if (!NS_IsInternalSameURIRedirect(aOldChannel, aNewChannel, aFlags)) {
rv = CheckRequestApproved(aOldChannel);
if (NS_FAILED(rv)) {
rv = LogBlockedRequest(aOldChannel);
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to log blocked cross-site request");
if (sPreflightCache) {
nsCOMPtr<nsIURI> oldURI;
NS_GetFinalChannelURI(aOldChannel, getter_AddRefs(oldURI));