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; #ifdef DEBUG // Make sure we're seeing the channel that we expect. nsCOMPtr<nsIRequest> requestDebug; nsresult rvDebug = aLoader->GetRequest(getter_AddRefs(requestDebug)); // When we cancel sometimes we get null here. That should be ok, but only if // we're canceled. NS_ASSERTION(NS_SUCCEEDED(rvDebug) || mCanceled, "GetRequest failed!"); if (NS_SUCCEEDED(rvDebug)) { nsCOMPtr<nsIChannel> channel(do_QueryInterface(requestDebug)); NS_ASSERTION(channel, "QI failed!"); nsCOMPtr<nsISupports> thisChannel(do_QueryInterface(channel)); NS_ASSERTION(thisChannel, "QI failed!"); nsCOMPtr<nsISupports> ourChannel(do_QueryInterface(loadInfo.channel)); NS_ASSERTION(ourChannel, "QI failed!"); NS_ASSERTION(thisChannel == ourChannel, "Wrong channel!"); } #endif // Use an alias to keep rv and loadInfo.result in sync. nsresult& rv = loadInfo.result = aStatus; if (NS_FAILED(rv)) { return rv; } 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; } } nsIDocument* parentDoc = mWorker->Pool()->ParentDocument(); if (!parentDoc) { NS_ASSERTION(mWorker->IsCanceled(), "Null parent document when we're not canceled?!"); return rv = NS_ERROR_FAILURE; } // 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; loadInfo.finalURI->GetSpec(filename); 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)); } 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; }
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; }