nsresult CViewSourceHTML::CreateViewSourceURL(const nsAString& linkUrl, nsString& viewSourceUrl) { nsCOMPtr<nsIURI> baseURI; nsCOMPtr<nsIURI> hrefURI; nsresult rv; // Default the view source URL to the empty string in case we fail. viewSourceUrl.Truncate(); // Get the BaseURI. rv = GetBaseURI(getter_AddRefs(baseURI)); NS_ENSURE_SUCCESS(rv, rv); // Use the link URL and the base URI to build a URI for the link. Note that // the link URL may have untranslated entities in it. nsAutoString expandedLinkUrl; ExpandEntities(linkUrl, expandedLinkUrl); rv = NS_NewURI(getter_AddRefs(hrefURI), expandedLinkUrl, mCharset.get(), baseURI); NS_ENSURE_SUCCESS(rv, rv); // Get the absolute URL from the link URI. nsCString absoluteLinkUrl; hrefURI->GetSpec(absoluteLinkUrl); // URLs that execute script (e.g. "javascript:" URLs) should just be // ignored. There's nothing reasonable we can do with them, and allowing // them to execute in the context of the view-source window presents a // security risk. Just return the empty string in this case. PRBool openingExecutesScript = PR_FALSE; rv = NS_URIChainHasFlags(hrefURI, nsIProtocolHandler::URI_OPENING_EXECUTES_SCRIPT, &openingExecutesScript); NS_ENSURE_SUCCESS(rv, NS_OK); // if there's an error, return the empty string if (openingExecutesScript) { return NS_OK; } // URLs that return data (e.g. "http:" URLs) should be prefixed with // "view-source:". URLs that don't return data should just be returned // undecorated. PRBool doesNotReturnData = PR_FALSE; rv = NS_URIChainHasFlags(hrefURI, nsIProtocolHandler::URI_DOES_NOT_RETURN_DATA, &doesNotReturnData); NS_ENSURE_SUCCESS(rv, NS_OK); // if there's an error, return the empty string if (!doesNotReturnData) { viewSourceUrl.AssignLiteral("view-source:"); } viewSourceUrl.AppendWithConversion(absoluteLinkUrl); return NS_OK; }
// Helper method for ShouldLoad() // Checks a URI for the given flags. Returns true if the URI has the flags, // and false if not (or if we weren't able to tell). static bool HasFlags(nsIURI* aURI, uint32_t aURIFlags) { bool hasFlags; nsresult rv = NS_URIChainHasFlags(aURI, aURIFlags, &hasFlags); return NS_SUCCEEDED(rv) && hasFlags; }
NS_IMETHODIMP nsCookiePermission::CanAccess(nsIURI *aURI, nsIChannel *aChannel, nsCookieAccess *aResult) { // Check this protocol doesn't allow cookies bool hasFlags; nsresult rv = NS_URIChainHasFlags(aURI, nsIProtocolHandler::URI_FORBIDS_COOKIE_ACCESS, &hasFlags); if (NS_FAILED(rv) || hasFlags) { *aResult = ACCESS_DENY; return NS_OK; } // Lazily initialize ourselves if (!EnsureInitialized()) return NS_ERROR_UNEXPECTED; // finally, check with permission manager... rv = mPermMgr->TestPermission(aURI, kPermissionType, (uint32_t *) aResult); if (NS_SUCCEEDED(rv)) { if (*aResult == nsICookiePermission::ACCESS_SESSION) { *aResult = nsICookiePermission::ACCESS_ALLOW; } } return rv; }
static bool URIHasFlags(nsIURI* aURI, uint32_t aURIFlags) { bool hasFlags; nsresult rv = NS_URIChainHasFlags(aURI, aURIFlags, &hasFlags); NS_ENSURE_SUCCESS(rv, false); return hasFlags; }
NS_IMETHODIMP nsAboutRedirector::NewChannel(nsIURI* aURI, nsILoadInfo* aLoadInfo, nsIChannel** aResult) { NS_ENSURE_ARG_POINTER(aURI); NS_ASSERTION(aResult, "must not be null"); nsAutoCString path; nsresult rv = NS_GetAboutModuleName(aURI, path); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv); NS_ENSURE_SUCCESS(rv, rv); for (int i = 0; i < kRedirTotal; i++) { if (!strcmp(path.get(), kRedirMap[i].id)) { nsCOMPtr<nsIChannel> tempChannel; nsCOMPtr<nsIURI> tempURI; rv = NS_NewURI(getter_AddRefs(tempURI), kRedirMap[i].url); NS_ENSURE_SUCCESS(rv, rv); // If tempURI links to an external URI (i.e. something other than // chrome:// or resource://) then set the LOAD_REPLACE flag on the // channel which forces the channel owner to reflect the displayed // URL rather then being the systemPrincipal. bool isUIResource = false; rv = NS_URIChainHasFlags(tempURI, nsIProtocolHandler::URI_IS_UI_RESOURCE, &isUIResource); NS_ENSURE_SUCCESS(rv, rv); bool isAboutBlank = NS_IsAboutBlank(tempURI); nsLoadFlags loadFlags = isUIResource || isAboutBlank ? static_cast<nsLoadFlags>(nsIChannel::LOAD_NORMAL) : static_cast<nsLoadFlags>(nsIChannel::LOAD_REPLACE); rv = NS_NewChannelInternal(getter_AddRefs(tempChannel), tempURI, aLoadInfo, nullptr, // aLoadGroup nullptr, // aCallbacks loadFlags); NS_ENSURE_SUCCESS(rv, rv); tempChannel->SetOriginalURI(aURI); tempChannel.forget(aResult); return rv; } } NS_ERROR("nsAboutRedirector called for unknown case"); return NS_ERROR_ILLEGAL_VALUE; }
nsresult ResourceReader::OnWalkURI(nsIURI* aURI, nsContentPolicyType aContentPolicyType) { // Test if this URI should be persisted. By default // we should assume the URI is persistable. bool doNotPersistURI; nsresult rv = NS_URIChainHasFlags( aURI, nsIProtocolHandler::URI_NON_PERSISTABLE, &doNotPersistURI); if (NS_SUCCEEDED(rv) && doNotPersistURI) { return NS_OK; } nsAutoCString stringURI; rv = aURI->GetSpec(stringURI); NS_ENSURE_SUCCESS(rv, rv); return mVisitor->VisitResource(mParent, stringURI, aContentPolicyType); }
NS_IMETHODIMP nsNoDataProtocolContentPolicy::ShouldLoad(uint32_t aContentType, nsIURI *aContentLocation, nsIURI *aRequestingLocation, nsISupports *aRequestingContext, const nsACString &aMimeGuess, nsISupports *aExtra, nsIPrincipal *aRequestPrincipal, int16_t *aDecision) { MOZ_ASSERT(aContentType == nsContentUtils::InternalContentPolicyTypeToExternal(aContentType), "We should only see external content policy types here."); *aDecision = nsIContentPolicy::ACCEPT; // Don't block for TYPE_OBJECT since such URIs are sometimes loaded by the // plugin, so they don't necessarily open external apps // TYPE_WEBSOCKET loads can only go to ws:// or wss://, so we don't need to // concern ourselves with them. if (aContentType != TYPE_DOCUMENT && aContentType != TYPE_SUBDOCUMENT && aContentType != TYPE_OBJECT && aContentType != TYPE_WEBSOCKET) { // The following are just quick-escapes for the most common cases // where we would allow the content to be loaded anyway. nsAutoCString scheme; aContentLocation->GetScheme(scheme); if (scheme.EqualsLiteral("http") || scheme.EqualsLiteral("https") || scheme.EqualsLiteral("ftp") || scheme.EqualsLiteral("file") || scheme.EqualsLiteral("chrome")) { return NS_OK; } bool shouldBlock; nsresult rv = NS_URIChainHasFlags(aContentLocation, nsIProtocolHandler::URI_DOES_NOT_RETURN_DATA, &shouldBlock); if (NS_SUCCEEDED(rv) && shouldBlock) { *aDecision = nsIContentPolicy::REJECT_REQUEST; } } return NS_OK; }
NS_IMETHODIMP nsCookiePermission::CanAccess(nsIURI *aURI, nsIChannel *aChannel, nsCookieAccess *aResult) { // Check this protocol doesn't allow cookies bool hasFlags; nsresult rv = NS_URIChainHasFlags(aURI, nsIProtocolHandler::URI_FORBIDS_COOKIE_ACCESS, &hasFlags); if (NS_FAILED(rv) || hasFlags) { *aResult = ACCESS_DENY; return NS_OK; } // Lazily initialize ourselves if (!EnsureInitialized()) return NS_ERROR_UNEXPECTED; // finally, check with permission manager... rv = mPermMgr->TestPermission(aURI, kPermissionType, (PRUint32 *) aResult); if (NS_SUCCEEDED(rv)) { switch (*aResult) { // if we have one of the publicly-available values, just return it case nsIPermissionManager::UNKNOWN_ACTION: // ACCESS_DEFAULT case nsIPermissionManager::ALLOW_ACTION: // ACCESS_ALLOW case nsIPermissionManager::DENY_ACTION: // ACCESS_DENY break; // ACCESS_SESSION means the cookie can be accepted; the session // downgrade will occur in CanSetCookie(). case nsICookiePermission::ACCESS_SESSION: *aResult = ACCESS_ALLOW; break; // ack, an unknown type! just use the defaults. default: *aResult = ACCESS_DEFAULT; } } return rv; }
NS_IMETHODIMP nsNoDataProtocolContentPolicy::ShouldLoad(PRUint32 aContentType, nsIURI *aContentLocation, nsIURI *aRequestingLocation, nsISupports *aRequestingContext, const nsACString &aMimeGuess, nsISupports *aExtra, PRInt16 *aDecision) { *aDecision = nsIContentPolicy::ACCEPT; // Don't block for TYPE_OBJECT since such URIs are sometimes loaded by the // plugin, so they don't neccesarily open external apps if (aContentType != TYPE_DOCUMENT && aContentType != TYPE_SUBDOCUMENT && aContentType != TYPE_OBJECT) { // The following are just quick-escapes for the most common cases // where we would allow the content to be loaded anyway. nsCAutoString scheme; aContentLocation->GetScheme(scheme); if (scheme.EqualsLiteral("http") || scheme.EqualsLiteral("https") || scheme.EqualsLiteral("ftp") || scheme.EqualsLiteral("file") || scheme.EqualsLiteral("chrome")) { return NS_OK; } PRBool shouldBlock; nsresult rv = NS_URIChainHasFlags(aContentLocation, nsIProtocolHandler::URI_DOES_NOT_RETURN_DATA, &shouldBlock); if (NS_SUCCEEDED(rv) && shouldBlock) { *aDecision = nsIContentPolicy::REJECT_REQUEST; } } return NS_OK; }
nsresult nsUserFontSet::StartLoad(gfxFontEntry *aFontToLoad, const gfxFontFaceSrc *aFontFaceSrc) { nsresult rv; // check same-site origin nsIPresShell *ps = mPresContext->PresShell(); if (!ps) return NS_ERROR_FAILURE; NS_ASSERTION(aFontFaceSrc && !aFontFaceSrc->mIsLocal, "bad font face url passed to fontloader"); NS_ASSERTION(aFontFaceSrc->mURI, "null font uri"); if (!aFontFaceSrc->mURI) return NS_ERROR_FAILURE; // use document principal, original principal if flag set // this enables user stylesheets to load font files via // @font-face rules nsCOMPtr<nsIPrincipal> principal = ps->GetDocument()->NodePrincipal(); NS_ASSERTION(aFontFaceSrc->mOriginPrincipal, "null origin principal in @font-face rule"); if (aFontFaceSrc->mUseOriginPrincipal) { principal = do_QueryInterface(aFontFaceSrc->mOriginPrincipal); } rv = nsFontFaceLoader::CheckLoadAllowed(principal, aFontFaceSrc->mURI, ps->GetDocument()); if (NS_FAILED(rv)) { #ifdef PR_LOGGING if (LOG_ENABLED()) { nsCAutoString fontURI, referrerURI; aFontFaceSrc->mURI->GetSpec(fontURI); if (aFontFaceSrc->mReferrer) aFontFaceSrc->mReferrer->GetSpec(referrerURI); LOG(("fontdownloader download blocked - font uri: (%s) " "referrer uri: (%s) err: %8.8x\n", fontURI.get(), referrerURI.get(), rv)); } #endif return rv; } nsCOMPtr<nsIStreamLoader> streamLoader; nsCOMPtr<nsILoadGroup> loadGroup(ps->GetDocument()->GetDocumentLoadGroup()); nsCOMPtr<nsIChannel> channel; // get Content Security Policy from principal to pass into channel nsCOMPtr<nsIChannelPolicy> channelPolicy; nsCOMPtr<nsIContentSecurityPolicy> csp; rv = principal->GetCsp(getter_AddRefs(csp)); NS_ENSURE_SUCCESS(rv, rv); if (csp) { channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1"); channelPolicy->SetContentSecurityPolicy(csp); channelPolicy->SetLoadType(nsIContentPolicy::TYPE_FONT); } rv = NS_NewChannel(getter_AddRefs(channel), aFontFaceSrc->mURI, nsnull, loadGroup, nsnull, nsIRequest::LOAD_NORMAL, channelPolicy); NS_ENSURE_SUCCESS(rv, rv); nsRefPtr<nsFontFaceLoader> fontLoader = new nsFontFaceLoader(aFontToLoad, aFontFaceSrc->mURI, this, channel); if (!fontLoader) return NS_ERROR_OUT_OF_MEMORY; #ifdef PR_LOGGING if (LOG_ENABLED()) { nsCAutoString fontURI, referrerURI; aFontFaceSrc->mURI->GetSpec(fontURI); if (aFontFaceSrc->mReferrer) aFontFaceSrc->mReferrer->GetSpec(referrerURI); LOG(("fontdownloader (%p) download start - font uri: (%s) " "referrer uri: (%s)\n", fontLoader.get(), fontURI.get(), referrerURI.get())); } #endif nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel)); if (httpChannel) httpChannel->SetReferrer(aFontFaceSrc->mReferrer); rv = NS_NewStreamLoader(getter_AddRefs(streamLoader), fontLoader); NS_ENSURE_SUCCESS(rv, rv); PRBool inherits = PR_FALSE; rv = NS_URIChainHasFlags(aFontFaceSrc->mURI, nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT, &inherits); if (NS_SUCCEEDED(rv) && inherits) { // allow data, javascript, etc URI's rv = channel->AsyncOpen(streamLoader, nsnull); } else { nsCOMPtr<nsIStreamListener> listener = new nsCrossSiteListenerProxy(streamLoader, principal, channel, PR_FALSE, &rv); if (NS_FAILED(rv)) { fontLoader->DropChannel(); // explicitly need to break ref cycle } NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY); NS_ENSURE_SUCCESS(rv, rv); rv = channel->AsyncOpen(listener, nsnull); } if (NS_SUCCEEDED(rv)) { mLoaders.PutEntry(fontLoader); } return rv; }
nsresult nsChannelClassifier::Start(nsIChannel *aChannel) { // Don't bother to run the classifier on a load that has already failed. // (this might happen after a redirect) PRUint32 status; aChannel->GetStatus(&status); if (NS_FAILED(status)) return NS_OK; // Don't bother to run the classifier on a cached load that was // previously classified. if (HasBeenClassified(aChannel)) { return NS_OK; } nsCOMPtr<nsIURI> uri; nsresult rv = aChannel->GetURI(getter_AddRefs(uri)); NS_ENSURE_SUCCESS(rv, rv); // Don't bother checking certain types of URIs. bool hasFlags; rv = NS_URIChainHasFlags(uri, nsIProtocolHandler::URI_DANGEROUS_TO_LOAD, &hasFlags); NS_ENSURE_SUCCESS(rv, rv); if (hasFlags) return NS_OK; rv = NS_URIChainHasFlags(uri, nsIProtocolHandler::URI_IS_LOCAL_FILE, &hasFlags); NS_ENSURE_SUCCESS(rv, rv); if (hasFlags) return NS_OK; rv = NS_URIChainHasFlags(uri, nsIProtocolHandler::URI_IS_UI_RESOURCE, &hasFlags); NS_ENSURE_SUCCESS(rv, rv); if (hasFlags) return NS_OK; rv = NS_URIChainHasFlags(uri, nsIProtocolHandler::URI_IS_LOCAL_RESOURCE, &hasFlags); NS_ENSURE_SUCCESS(rv, rv); if (hasFlags) return NS_OK; nsCOMPtr<nsIURIClassifier> uriClassifier = do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID, &rv); if (rv == NS_ERROR_FACTORY_NOT_REGISTERED || rv == NS_ERROR_NOT_AVAILABLE) { // no URI classifier, ignore this failure. return NS_OK; } NS_ENSURE_SUCCESS(rv, rv); bool expectCallback; rv = uriClassifier->Classify(uri, this, &expectCallback); if (NS_FAILED(rv)) return rv; if (expectCallback) { // Suspend the channel, it will be resumed when we get the classifier // callback. rv = aChannel->Suspend(); if (NS_FAILED(rv)) { // Some channels (including nsJSChannel) fail on Suspend. This // shouldn't be fatal, but will prevent malware from being // blocked on these channels. return NS_OK; } mSuspendedChannel = aChannel; #ifdef DEBUG LOG(("nsChannelClassifier[%p]: suspended channel %p", this, mSuspendedChannel.get())); #endif } return NS_OK; }
NS_IMETHODIMP nsAboutRedirector::NewChannel(nsIURI* aURI, nsILoadInfo* aLoadInfo, nsIChannel** aResult) { NS_ENSURE_ARG_POINTER(aURI); NS_ENSURE_ARG_POINTER(aLoadInfo); NS_ASSERTION(aResult, "must not be null"); nsAutoCString path; nsresult rv = NS_GetAboutModuleName(aURI, path); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv); NS_ENSURE_SUCCESS(rv, rv); if (path.EqualsASCII("crashparent") || path.EqualsASCII("crashcontent")) { nsCOMPtr<nsIChannel> channel = new CrashChannel(aURI); channel.forget(aResult); return NS_OK; } #ifdef ABOUT_CONFIG_BLOCKED_GV // We don't want to allow access to about:config from // GeckoView on release or beta, but it's fine for Fennec. if (path.EqualsASCII("config") && !mozilla::jni::IsFennec()) { return NS_ERROR_NOT_AVAILABLE; } #endif for (int i = 0; i < kRedirTotal; i++) { if (!strcmp(path.get(), kRedirMap[i].id)) { nsCOMPtr<nsIChannel> tempChannel; nsCOMPtr<nsIURI> tempURI; rv = NS_NewURI(getter_AddRefs(tempURI), kRedirMap[i].url); NS_ENSURE_SUCCESS(rv, rv); rv = NS_NewChannelInternal(getter_AddRefs(tempChannel), tempURI, aLoadInfo); NS_ENSURE_SUCCESS(rv, rv); // If tempURI links to an external URI (i.e. something other than // chrome:// or resource://) then set result principal URI on the // load info which forces the channel principal to reflect the displayed // URL rather then being the systemPrincipal. bool isUIResource = false; rv = NS_URIChainHasFlags(tempURI, nsIProtocolHandler::URI_IS_UI_RESOURCE, &isUIResource); NS_ENSURE_SUCCESS(rv, rv); bool isAboutBlank = NS_IsAboutBlank(tempURI); if (!isUIResource && !isAboutBlank) { aLoadInfo->SetResultPrincipalURI(tempURI); } tempChannel->SetOriginalURI(aURI); tempChannel.forget(aResult); return rv; } } NS_ERROR("nsAboutRedirector called for unknown case"); return NS_ERROR_ILLEGAL_VALUE; }
nsresult nsDOMWorkerScriptLoader::OnStreamCompleteInternal(nsIStreamLoader* aLoader, nsISupports* aContext, nsresult aStatus, PRUint32 aStringLen, const PRUint8* aString) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); nsCOMPtr<nsISupportsPRUint32> indexSupports(do_QueryInterface(aContext)); NS_ENSURE_TRUE(indexSupports, NS_ERROR_NO_INTERFACE); PRUint32 index = PR_UINT32_MAX; indexSupports->GetData(&index); if (index >= mScriptCount) { NS_NOTREACHED("This really can't fail or we'll hang!"); return NS_ERROR_FAILURE; } ScriptLoadInfo& loadInfo = mLoadInfos[index]; NS_ASSERTION(!loadInfo.done, "Got complete on the same load twice!"); loadInfo.done = PR_TRUE; // Use an alias to keep rv and loadInfo.result in sync. nsresult& rv = loadInfo.result; if (NS_FAILED(aStatus)) { return rv = aStatus; } if (!(aStringLen && aString)) { return rv = NS_ERROR_UNEXPECTED; } // Make sure we're not seeing the result of a 404 or something by checking the // 'requestSucceeded' attribute on the http channel. nsCOMPtr<nsIRequest> request; rv = aLoader->GetRequest(getter_AddRefs(request)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(request); if (httpChannel) { PRBool requestSucceeded; rv = httpChannel->GetRequestSucceeded(&requestSucceeded); NS_ENSURE_SUCCESS(rv, rv); if (!requestSucceeded) { return rv = NS_ERROR_NOT_AVAILABLE; } } // May be null. nsIDocument* parentDoc = mWorker->Pool()->ParentDocument(); // Use the regular nsScriptLoader for this grunt work! Should be just fine // because we're running on the main thread. rv = nsScriptLoader::ConvertToUTF16(loadInfo.channel, aString, aStringLen, EmptyString(), parentDoc, loadInfo.scriptText); if (NS_FAILED(rv)) { return rv; } if (loadInfo.scriptText.IsEmpty()) { return rv = NS_ERROR_FAILURE; } nsCString filename; rv = loadInfo.finalURI->GetSpec(filename); NS_ENSURE_SUCCESS(rv, rv); if (filename.IsEmpty()) { filename.Assign(NS_LossyConvertUTF16toASCII(loadInfo.url)); } else { // This will help callers figure out what their script url resolved to in // case of errors. loadInfo.url.Assign(NS_ConvertUTF8toUTF16(filename)); } // Update the principal of the worker and its base URI if we just loaded the // worker's primary script. if (mForWorker) { nsCOMPtr<nsIChannel> channel = do_QueryInterface(request); NS_ASSERTION(channel, "This should never fail!"); // Take care of the base URI first. nsCOMPtr<nsIURI> finalURI; rv = NS_GetFinalChannelURI(channel, getter_AddRefs(finalURI)); NS_ENSURE_SUCCESS(rv, rv); mWorker->SetBaseURI(finalURI); // Now to figure out which principal to give this worker. nsRefPtr<nsDOMWorker> parent = mWorker->GetParent(); NS_ASSERTION(mWorker->GetPrincipal() || parent, "Must have one of these!"); nsCOMPtr<nsIPrincipal> loadPrincipal = mWorker->GetPrincipal() ? mWorker->GetPrincipal() : parent->GetPrincipal(); nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager(); NS_ASSERTION(ssm, "Should never be null!"); nsCOMPtr<nsIPrincipal> channelPrincipal; rv = ssm->GetChannelPrincipal(channel, getter_AddRefs(channelPrincipal)); NS_ENSURE_SUCCESS(rv, rv); // See if this is a resource URI. Since JSMs usually come from resource:// // URIs we're currently considering all URIs with the URI_IS_UI_RESOURCE // flag as valid for creating privileged workers. if (!nsContentUtils::IsSystemPrincipal(channelPrincipal)) { PRBool isResource; rv = NS_URIChainHasFlags(finalURI, nsIProtocolHandler::URI_IS_UI_RESOURCE, &isResource); NS_ENSURE_SUCCESS(rv, rv); if (isResource) { rv = ssm->GetSystemPrincipal(getter_AddRefs(channelPrincipal)); NS_ENSURE_SUCCESS(rv, rv); } } // If the load principal is the system principal then the channel principal // must also be the system principal (we do not allow chrome code to create // workers with non-chrome scripts). Otherwise this channel principal must // be same origin with the load principal (we check again here in case // redirects changed the location of the script). if (nsContentUtils::IsSystemPrincipal(loadPrincipal)) { if (!nsContentUtils::IsSystemPrincipal(channelPrincipal)) { return rv = NS_ERROR_DOM_BAD_URI; } } else if (NS_FAILED(loadPrincipal->CheckMayLoad(finalURI, PR_FALSE))) { return rv = NS_ERROR_DOM_BAD_URI; } mWorker->SetPrincipal(channelPrincipal); } nsRefPtr<ScriptCompiler> compiler = new ScriptCompiler(this, loadInfo.scriptText, filename, loadInfo.scriptObj); NS_ASSERTION(compiler, "Out of memory!"); if (!compiler) { return rv = NS_ERROR_OUT_OF_MEMORY; } rv = mTarget->Dispatch(compiler, NS_DISPATCH_NORMAL); NS_ENSURE_SUCCESS(rv, rv); return rv; }
NS_IMETHODIMP nsDataDocumentContentPolicy::ShouldLoad(PRUint32 aContentType, nsIURI *aContentLocation, nsIURI *aRequestingLocation, nsISupports *aRequestingContext, const nsACString &aMimeGuess, nsISupports *aExtra, PRInt16 *aDecision) { *aDecision = nsIContentPolicy::ACCEPT; // Look for the document. In most cases, aRequestingContext is a node. nsCOMPtr<nsIDocument> doc; nsCOMPtr<nsINode> node = do_QueryInterface(aRequestingContext); if (node) { doc = node->GetOwnerDoc(); } else { nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(aRequestingContext); if (window) { nsCOMPtr<nsIDOMDocument> domDoc; window->GetDocument(getter_AddRefs(domDoc)); doc = do_QueryInterface(domDoc); } } // DTDs are always OK to load if (!doc || aContentType == nsIContentPolicy::TYPE_DTD) { return NS_OK; } // Nothing else is OK to load for data documents if (doc->IsLoadedAsData()) { *aDecision = nsIContentPolicy::REJECT_TYPE; return NS_OK; } if (doc->IsBeingUsedAsImage()) { // Allow local resources for SVG-as-an-image documents, but disallow // everything else, to prevent data leakage PRBool hasFlags; nsresult rv = NS_URIChainHasFlags(aContentLocation, nsIProtocolHandler::URI_IS_LOCAL_RESOURCE, &hasFlags); if (NS_FAILED(rv) || !hasFlags) { // resource is not local (or we couldn't tell) - reject! *aDecision = nsIContentPolicy::REJECT_TYPE; // report error, if we can. if (node) { nsIPrincipal* requestingPrincipal = node->NodePrincipal(); nsRefPtr<nsIURI> principalURI; rv = requestingPrincipal->GetURI(getter_AddRefs(principalURI)); if (NS_SUCCEEDED(rv) && principalURI) { nsScriptSecurityManager::ReportError( nsnull, NS_LITERAL_STRING("CheckSameOriginError"), principalURI, aContentLocation); } } } else if (aContentType == nsIContentPolicy::TYPE_IMAGE && doc->GetDocumentURI()) { // Check for (& disallow) recursive image-loads PRBool isRecursiveLoad; rv = aContentLocation->EqualsExceptRef(doc->GetDocumentURI(), &isRecursiveLoad); if (NS_FAILED(rv) || isRecursiveLoad) { NS_WARNING("Refusing to recursively load image"); *aDecision = nsIContentPolicy::REJECT_TYPE; } } return NS_OK; } // Allow all loads for non-external-resource documents if (!doc->GetDisplayDocument()) { return NS_OK; } // For external resources, blacklist some load types if (aContentType == nsIContentPolicy::TYPE_OBJECT || aContentType == nsIContentPolicy::TYPE_DOCUMENT || aContentType == nsIContentPolicy::TYPE_SUBDOCUMENT || aContentType == nsIContentPolicy::TYPE_SCRIPT) { *aDecision = nsIContentPolicy::REJECT_TYPE; } return NS_OK; }
/* void onChannelRedirect (in nsIChannel oldChannel, in nsIChannel newChannel, in unsigned long flags); */ NS_IMETHODIMP imgRequest::OnChannelRedirect(nsIChannel *oldChannel, nsIChannel *newChannel, PRUint32 flags) { NS_ASSERTION(mRequest && mChannel, "Got an OnChannelRedirect after we nulled out mRequest!"); NS_ASSERTION(mChannel == oldChannel, "Got a channel redirect for an unknown channel!"); NS_ASSERTION(newChannel, "Got a redirect to a NULL channel!"); nsresult rv = NS_OK; nsCOMPtr<nsIChannelEventSink> sink(do_GetInterface(mPrevChannelSink)); if (sink) { rv = sink->OnChannelRedirect(oldChannel, newChannel, flags); if (NS_FAILED(rv)) return rv; } mChannel = newChannel; // Don't make any cache changes if we're going to point to the same thing. We // compare specs and not just URIs here because URIs that compare as // .Equals() might have different hashes. nsCAutoString oldspec; if (mKeyURI) mKeyURI->GetSpec(oldspec); LOG_MSG_WITH_PARAM(gImgLog, "imgRequest::OnChannelRedirect", "old", oldspec.get()); // make sure we have a protocol that returns data rather than opens // an external application, e.g. mailto: nsCOMPtr<nsIURI> uri; newChannel->GetURI(getter_AddRefs(uri)); PRBool doesNotReturnData = PR_FALSE; rv = NS_URIChainHasFlags(uri, nsIProtocolHandler::URI_DOES_NOT_RETURN_DATA, &doesNotReturnData); if (NS_FAILED(rv)) return rv; if (doesNotReturnData) return NS_ERROR_ABORT; nsCOMPtr<nsIURI> newURI; newChannel->GetOriginalURI(getter_AddRefs(newURI)); nsCAutoString newspec; if (newURI) newURI->GetSpec(newspec); LOG_MSG_WITH_PARAM(gImgLog, "imgRequest::OnChannelRedirect", "new", newspec.get()); if (oldspec != newspec) { if (mIsInCache) { // Remove the cache entry from the cache, but don't null out mCacheEntry // (as imgRequest::RemoveFromCache() does), because we need it to put // ourselves back in the cache. if (mCacheEntry) imgLoader::RemoveFromCache(mCacheEntry); else imgLoader::RemoveFromCache(mKeyURI); } mKeyURI = newURI; if (mIsInCache) { // If we don't still have a URI or cache entry, we don't want to put // ourselves back into the cache. if (mKeyURI && mCacheEntry) imgLoader::PutIntoCache(mKeyURI, mCacheEntry); } } return rv; }
nsresult nsChannelClassifier::StartInternal() { // Should only be called in the parent process. MOZ_ASSERT(XRE_IsParentProcess()); // Don't bother to run the classifier on a load that has already failed. // (this might happen after a redirect) nsresult status; mChannel->GetStatus(&status); if (NS_FAILED(status)) return status; // Don't bother to run the classifier on a cached load that was // previously classified as good. if (HasBeenClassified(mChannel)) { return NS_ERROR_UNEXPECTED; } nsCOMPtr<nsIURI> uri; nsresult rv = mChannel->GetURI(getter_AddRefs(uri)); NS_ENSURE_SUCCESS(rv, rv); // Don't bother checking certain types of URIs. bool hasFlags; rv = NS_URIChainHasFlags(uri, nsIProtocolHandler::URI_DANGEROUS_TO_LOAD, &hasFlags); NS_ENSURE_SUCCESS(rv, rv); if (hasFlags) return NS_ERROR_UNEXPECTED; rv = NS_URIChainHasFlags(uri, nsIProtocolHandler::URI_IS_LOCAL_FILE, &hasFlags); NS_ENSURE_SUCCESS(rv, rv); if (hasFlags) return NS_ERROR_UNEXPECTED; rv = NS_URIChainHasFlags(uri, nsIProtocolHandler::URI_IS_UI_RESOURCE, &hasFlags); NS_ENSURE_SUCCESS(rv, rv); if (hasFlags) return NS_ERROR_UNEXPECTED; rv = NS_URIChainHasFlags(uri, nsIProtocolHandler::URI_IS_LOCAL_RESOURCE, &hasFlags); NS_ENSURE_SUCCESS(rv, rv); if (hasFlags) return NS_ERROR_UNEXPECTED; // Skip whitelisted hostnames. nsAutoCString whitelisted; Preferences::GetCString("urlclassifier.skipHostnames", &whitelisted); if (!whitelisted.IsEmpty()) { ToLowerCase(whitelisted); LOG(("nsChannelClassifier[%p]:StartInternal whitelisted hostnames = %s", this, whitelisted.get())); if (IsHostnameWhitelisted(uri, whitelisted)) { return NS_ERROR_UNEXPECTED; } } nsCOMPtr<nsIURIClassifier> uriClassifier = do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID, &rv); if (rv == NS_ERROR_FACTORY_NOT_REGISTERED || rv == NS_ERROR_NOT_AVAILABLE) { // no URI classifier, ignore this failure. return NS_ERROR_NOT_AVAILABLE; } NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIScriptSecurityManager> securityManager = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIPrincipal> principal; rv = securityManager->GetChannelURIPrincipal(mChannel, getter_AddRefs(principal)); NS_ENSURE_SUCCESS(rv, rv); bool expectCallback; bool trackingProtectionEnabled = false; (void)ShouldEnableTrackingProtection(mChannel, &trackingProtectionEnabled); if (LOG_ENABLED()) { nsCOMPtr<nsIURI> principalURI; principal->GetURI(getter_AddRefs(principalURI)); LOG(("nsChannelClassifier[%p]: Classifying principal %s on channel with " "uri %s", this, principalURI->GetSpecOrDefault().get(), uri->GetSpecOrDefault().get())); } rv = uriClassifier->Classify(principal, trackingProtectionEnabled, this, &expectCallback); if (NS_FAILED(rv)) { return rv; } if (expectCallback) { // Suspend the channel, it will be resumed when we get the classifier // callback. rv = mChannel->Suspend(); if (NS_FAILED(rv)) { // Some channels (including nsJSChannel) fail on Suspend. This // shouldn't be fatal, but will prevent malware from being // blocked on these channels. LOG(("nsChannelClassifier[%p]: Couldn't suspend channel", this)); return rv; } mSuspendedChannel = true; LOG(("nsChannelClassifier[%p]: suspended channel %p", this, mChannel.get())); } else { LOG(("nsChannelClassifier[%p]: not expecting callback", this)); return NS_ERROR_FAILURE; } return NS_OK; }