LCOV - app.info - dom/workers/ScriptLoader.cpp

LCOV - code coverage report
| Current view: | directory - dom/workers - ScriptLoader.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 308 | 0 | 0.0 %
| Date: | 2012-04-21 | Functions: | 25 | 0 | 0.0 %

           1                 : /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
           2                 : /* ***** BEGIN LICENSE BLOCK *****
           3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           4                 :  *
           5                 :  * The contents of this file are subject to the Mozilla Public License Version
           6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           7                 :  * the License. You may obtain a copy of the License at
           8                 :  * http://www.mozilla.org/MPL/
           9                 :  *
          10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          12                 :  * for the specific language governing rights and limitations under the
          13                 :  * License.
          14                 :  *
          15                 :  * The Original Code is Web Workers.
          16                 :  *
          17                 :  * The Initial Developer of the Original Code is
          18                 :  *   The Mozilla Foundation.
          19                 :  * Portions created by the Initial Developer are Copyright (C) 2011
          20                 :  * the Initial Developer. All Rights Reserved.
          21                 :  *
          22                 :  * Contributor(s):
          23                 :  *   Ben Turner <bent.mozilla@gmail.com> (Original Author)
          24                 :  *
          25                 :  * Alternatively, the contents of this file may be used under the terms of
          26                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
          27                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          29                 :  * of those above. If you wish to allow use of your version of this file only
          30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          31                 :  * use your version of this file under the terms of the MPL, indicate your
          32                 :  * decision by deleting the provisions above and replace them with the notice
          33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          34                 :  * the provisions above, a recipient may use your version of this file under
          35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          36                 :  *
          37                 :  * ***** END LICENSE BLOCK ***** */
          38                 :
          39                 : #include "ScriptLoader.h"
          40                 :
          41                 : #include "nsIChannel.h"
          42                 : #include "nsIChannelPolicy.h"
          43                 : #include "nsIContentPolicy.h"
          44                 : #include "nsIContentSecurityPolicy.h"
          45                 : #include "nsIHttpChannel.h"
          46                 : #include "nsIIOService.h"
          47                 : #include "nsIProtocolHandler.h"
          48                 : #include "nsIScriptSecurityManager.h"
          49                 : #include "nsIStreamLoader.h"
          50                 : #include "nsIURI.h"
          51                 :
          52                 : #include "jsapi.h"
          53                 : #include "nsChannelPolicy.h"
          54                 : #include "nsContentErrors.h"
          55                 : #include "nsContentPolicyUtils.h"
          56                 : #include "nsContentUtils.h"
          57                 : #include "nsDocShellCID.h"
          58                 : #include "nsISupportsPrimitives.h"
          59                 : #include "nsNetError.h"
          60                 : #include "nsNetUtil.h"
          61                 : #include "nsScriptLoader.h"
          62                 : #include "nsStringGlue.h"
          63                 : #include "nsTArray.h"
          64                 : #include "nsThreadUtils.h"
          65                 : #include "nsXPCOM.h"
          66                 :
          67                 : #include "Principal.h"
          68                 : #include "WorkerFeature.h"
          69                 : #include "WorkerPrivate.h"
          70                 :
          71                 : #define MAX_CONCURRENT_SCRIPTS 1000
          72                 :
          73                 : USING_WORKERS_NAMESPACE
          74                 :
          75                 : namespace {
          76                 :
          77                 : class ScriptLoaderRunnable;
          78                 :
          79                 : struct ScriptLoadInfo
          80               0 : {
          81               0 :   ScriptLoadInfo()
          82                 :   : mLoadResult(NS_ERROR_NOT_INITIALIZED), mExecutionScheduled(false),
          83               0 :     mExecutionResult(false)
          84               0 :   { }
          85                 :
          86                 :   bool
          87                 :   ReadyToExecute()
          88                 :   {
          89                 :     return !mChannel && NS_SUCCEEDED(mLoadResult) && !mExecutionScheduled;
          90                 :   }
          91                 :
          92                 :   nsString mURL;
          93                 :   nsCOMPtr<nsIChannel> mChannel;
          94                 :   nsString mScriptText;
          95                 :
          96                 :   nsresult mLoadResult;
          97                 :   bool mExecutionScheduled;
          98                 :   bool mExecutionResult;
          99                 : };
         100                 :
         101                 : class ScriptExecutorRunnable : public WorkerSyncRunnable
         102               0 : {
         103                 :   ScriptLoaderRunnable& mScriptLoader;
         104                 :   PRUint32 mFirstIndex;
         105                 :   PRUint32 mLastIndex;
         106                 :
         107                 : public:
         108                 :   ScriptExecutorRunnable(ScriptLoaderRunnable& aScriptLoader,
         109                 :                          PRUint32 aSyncQueueKey, PRUint32 aFirstIndex,
         110                 :                          PRUint32 aLastIndex);
         111                 :
         112                 :   bool
         113               0 :   PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
         114                 :   {
         115               0 :     AssertIsOnMainThread();
         116               0 :     return true;
         117                 :   }
         118                 :
         119                 :   void
         120               0 :   PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
         121                 :                bool aDispatchResult)
         122                 :   {
         123               0 :     AssertIsOnMainThread();
         124               0 :   }
         125                 :
         126                 :   bool
         127                 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate);
         128                 :
         129                 :   void
         130                 :   PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult);
         131                 : };
         132                 :
         133                 : class ScriptLoaderRunnable : public WorkerFeature,
         134                 :                              public nsIRunnable,
         135                 :                              public nsIStreamLoaderObserver
         136               0 : {
         137                 :   friend class ScriptExecutorRunnable;
         138                 :
         139                 :   WorkerPrivate* mWorkerPrivate;
         140                 :   PRUint32 mSyncQueueKey;
         141                 :   nsTArray<ScriptLoadInfo> mLoadInfos;
         142                 :   bool mIsWorkerScript;
         143                 :   bool mCanceled;
         144                 :   bool mCanceledMainThread;
         145                 :
         146                 : public:
         147                 :   NS_DECL_ISUPPORTS
         148                 :
         149               0 :   ScriptLoaderRunnable(WorkerPrivate* aWorkerPrivate,
         150                 :                        PRUint32 aSyncQueueKey,
         151                 :                        nsTArray<ScriptLoadInfo>& aLoadInfos,
         152                 :                        bool aIsWorkerScript)
         153                 :   : mWorkerPrivate(aWorkerPrivate), mSyncQueueKey(aSyncQueueKey),
         154                 :     mIsWorkerScript(aIsWorkerScript), mCanceled(false),
         155               0 :     mCanceledMainThread(false)
         156                 :   {
         157               0 :     aWorkerPrivate->AssertIsOnWorkerThread();
         158               0 :     NS_ASSERTION(!aIsWorkerScript || aLoadInfos.Length() == 1, "Bad args!");
         159                 :
         160               0 :     if (!mLoadInfos.SwapElements(aLoadInfos)) {
         161               0 :       NS_ERROR("This should never fail!");
         162                 :     }
         163               0 :   }
         164                 :
         165                 :   NS_IMETHOD
         166               0 :   Run()
         167                 :   {
         168               0 :     AssertIsOnMainThread();
         169                 :
         170               0 :     if (NS_FAILED(RunInternal())) {
         171               0 :       CancelMainThread();
         172                 :     }
         173                 :
         174               0 :     return NS_OK;
         175                 :   }
         176                 :
         177                 :   NS_IMETHOD
         178               0 :   OnStreamComplete(nsIStreamLoader* aLoader, nsISupports* aContext,
         179                 :                    nsresult aStatus, PRUint32 aStringLen,
         180                 :                    const PRUint8* aString)
         181                 :   {
         182               0 :     AssertIsOnMainThread();
         183                 :
         184               0 :     nsCOMPtr<nsISupportsPRUint32> indexSupports(do_QueryInterface(aContext));
         185               0 :     NS_ASSERTION(indexSupports, "This should never fail!");
         186                 :
         187               0 :     PRUint32 index = PR_UINT32_MAX;
         188               0 :     if (NS_FAILED(indexSupports->GetData(&index)) ||
         189               0 :         index >= mLoadInfos.Length()) {
         190               0 :       NS_ERROR("Bad index!");
         191                 :     }
         192                 :
         193               0 :     ScriptLoadInfo& loadInfo = mLoadInfos[index];
         194                 :
         195                 :     loadInfo.mLoadResult = OnStreamCompleteInternal(aLoader, aContext, aStatus,
         196                 :                                                     aStringLen, aString,
         197               0 :                                                     loadInfo);
         198                 :
         199               0 :     ExecuteFinishedScripts();
         200                 :
         201               0 :     return NS_OK;
         202                 :   }
         203                 :
         204                 :   bool
         205               0 :   Notify(JSContext* aCx, Status aStatus)
         206                 :   {
         207               0 :     mWorkerPrivate->AssertIsOnWorkerThread();
         208                 :
         209               0 :     if (aStatus >= Terminating && !mCanceled) {
         210               0 :       mCanceled = true;
         211                 :
         212                 :       nsCOMPtr<nsIRunnable> runnable =
         213               0 :         NS_NewRunnableMethod(this, &ScriptLoaderRunnable::CancelMainThread);
         214               0 :       NS_ASSERTION(runnable, "This should never fail!");
         215                 :
         216               0 :       if (NS_FAILED(NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL))) {
         217               0 :         JS_ReportError(aCx, "Failed to cancel script loader!");
         218               0 :         return false;
         219                 :       }
         220                 :     }
         221                 :
         222               0 :     return true;
         223                 :   }
         224                 :
         225                 :   void
         226               0 :   CancelMainThread()
         227                 :   {
         228               0 :     AssertIsOnMainThread();
         229                 :
         230               0 :     if (mCanceledMainThread) {
         231               0 :       return;
         232                 :     }
         233                 :
         234               0 :     mCanceledMainThread = true;
         235                 :
         236                 :     // Cancel all the channels that were already opened.
         237               0 :     for (PRUint32 index = 0; index < mLoadInfos.Length(); index++) {
         238               0 :       ScriptLoadInfo& loadInfo = mLoadInfos[index];
         239                 :
         240               0 :       if (loadInfo.mChannel &&
         241               0 :           NS_FAILED(loadInfo.mChannel->Cancel(NS_BINDING_ABORTED))) {
         242               0 :         NS_WARNING("Failed to cancel channel!");
         243               0 :         loadInfo.mChannel = nsnull;
         244               0 :         loadInfo.mLoadResult = NS_BINDING_ABORTED;
         245                 :       }
         246                 :     }
         247                 :
         248               0 :     ExecuteFinishedScripts();
         249                 :   }
         250                 :
         251                 :   nsresult
         252               0 :   RunInternal()
         253                 :   {
         254               0 :     AssertIsOnMainThread();
         255                 :
         256               0 :     WorkerPrivate* parentWorker = mWorkerPrivate->GetParent();
         257                 :
         258                 :     // Figure out which principal to use.
         259               0 :     nsIPrincipal* principal = mWorkerPrivate->GetPrincipal();
         260               0 :     if (!principal) {
         261               0 :       NS_ASSERTION(parentWorker, "Must have a principal!");
         262               0 :       NS_ASSERTION(mIsWorkerScript, "Must have a principal for importScripts!");
         263                 :
         264               0 :       principal = parentWorker->GetPrincipal();
         265                 :     }
         266               0 :     NS_ASSERTION(principal, "This should never be null here!");
         267                 :
         268                 :     // Figure out our base URI.
         269               0 :     nsCOMPtr<nsIURI> baseURI;
         270               0 :     if (mIsWorkerScript) {
         271               0 :       if (parentWorker) {
         272               0 :         baseURI = parentWorker->GetBaseURI();
         273               0 :         NS_ASSERTION(baseURI, "Should have been set already!");
         274                 :       }
         275                 :       else {
         276                 :         // May be null.
         277               0 :         baseURI = mWorkerPrivate->GetBaseURI();
         278                 :       }
         279                 :     }
         280                 :     else {
         281               0 :       baseURI = mWorkerPrivate->GetBaseURI();
         282               0 :       NS_ASSERTION(baseURI, "Should have been set already!");
         283                 :     }
         284                 :
         285                 :     // May be null.
         286               0 :     nsCOMPtr<nsIDocument> parentDoc = mWorkerPrivate->GetDocument();
         287                 :
         288                 :     // All of these can potentially be null, but that should be ok. We'll either
         289                 :     // succeed without them or fail below.
         290               0 :     nsCOMPtr<nsILoadGroup> loadGroup;
         291               0 :     if (parentDoc) {
         292               0 :       loadGroup = parentDoc->GetDocumentLoadGroup();
         293                 :     }
         294                 :
         295               0 :     nsCOMPtr<nsIIOService> ios(do_GetIOService());
         296                 :
         297               0 :     nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
         298               0 :     NS_ASSERTION(secMan, "This should never be null!");
         299                 :
         300               0 :     for (PRUint32 index = 0; index < mLoadInfos.Length(); index++) {
         301               0 :       ScriptLoadInfo& loadInfo = mLoadInfos[index];
         302               0 :       nsresult& rv = loadInfo.mLoadResult;
         303                 :
         304               0 :       nsCOMPtr<nsIURI> uri;
         305               0 :       rv = nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(uri),
         306                 :                                                      loadInfo.mURL, parentDoc,
         307               0 :                                                      baseURI);
         308               0 :       if (NS_FAILED(rv)) {
         309               0 :         return rv;
         310                 :       }
         311                 :
         312                 :       // If we're part of a document then check the content load policy.
         313               0 :       if (parentDoc) {
         314               0 :         PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
         315                 :         rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_SCRIPT, uri,
         316                 :                                        principal, parentDoc,
         317               0 :                                        NS_LITERAL_CSTRING("text/javascript"),
         318                 :                                        nsnull, &shouldLoad,
         319                 :                                        nsContentUtils::GetContentPolicy(),
         320               0 :                                        secMan);
         321               0 :         if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
         322               0 :           if (NS_FAILED(rv) || shouldLoad != nsIContentPolicy::REJECT_TYPE) {
         323               0 :             return rv = NS_ERROR_CONTENT_BLOCKED;
         324                 :           }
         325               0 :           return rv = NS_ERROR_CONTENT_BLOCKED_SHOW_ALT;
         326                 :         }
         327                 :       }
         328                 :
         329                 :       // If this script loader is being used to make a new worker then we need
         330                 :       // to do a same-origin check. Otherwise we need to clear the load with the
         331                 :       // security manager.
         332               0 :       if (mIsWorkerScript) {
         333               0 :         nsCString scheme;
         334               0 :         rv = uri->GetScheme(scheme);
         335               0 :         NS_ENSURE_SUCCESS(rv, rv);
         336                 :
         337                 :         // We exempt data URLs from the same origin check.
         338               0 :         if (!scheme.EqualsLiteral("data")) {
         339               0 :           rv = principal->CheckMayLoad(uri, false);
         340               0 :           NS_ENSURE_SUCCESS(rv, rv);
         341                 :         }
         342                 :       }
         343                 :       else {
         344               0 :         rv = secMan->CheckLoadURIWithPrincipal(principal, uri, 0);
         345               0 :         NS_ENSURE_SUCCESS(rv, rv);
         346                 :       }
         347                 :
         348                 :       // We need to know which index we're on in OnStreamComplete so we know
         349                 :       // where to put the result.
         350                 :       nsCOMPtr<nsISupportsPRUint32> indexSupports =
         351               0 :         do_CreateInstance(NS_SUPPORTS_PRUINT32_CONTRACTID, &rv);
         352               0 :       NS_ENSURE_SUCCESS(rv, rv);
         353                 :
         354               0 :       rv = indexSupports->SetData(index);
         355               0 :       NS_ENSURE_SUCCESS(rv, rv);
         356                 :
         357                 :       // We don't care about progress so just use the simple stream loader for
         358                 :       // OnStreamComplete notification only.
         359               0 :       nsCOMPtr<nsIStreamLoader> loader;
         360               0 :       rv = NS_NewStreamLoader(getter_AddRefs(loader), this);
         361               0 :       NS_ENSURE_SUCCESS(rv, rv);
         362                 :
         363                 :       // Get Content Security Policy from parent document to pass into channel.
         364               0 :       nsCOMPtr<nsIContentSecurityPolicy> csp;
         365               0 :       rv = principal->GetCsp(getter_AddRefs(csp));
         366               0 :       NS_ENSURE_SUCCESS(rv, rv);
         367                 :
         368               0 :       nsCOMPtr<nsIChannelPolicy> channelPolicy;
         369               0 :       if (csp) {
         370               0 :         channelPolicy = do_CreateInstance(NSCHANNELPOLICY_CONTRACTID, &rv);
         371               0 :         NS_ENSURE_SUCCESS(rv, rv);
         372                 :
         373               0 :         rv = channelPolicy->SetContentSecurityPolicy(csp);
         374               0 :         NS_ENSURE_SUCCESS(rv, rv);
         375                 :
         376               0 :         rv = channelPolicy->SetLoadType(nsIContentPolicy::TYPE_SCRIPT);
         377               0 :         NS_ENSURE_SUCCESS(rv, rv);
         378                 :       }
         379                 :
         380               0 :       PRUint32 flags = nsIRequest::LOAD_NORMAL | nsIChannel::LOAD_CLASSIFY_URI;
         381                 :
         382               0 :       nsCOMPtr<nsIChannel> channel;
         383               0 :       rv = NS_NewChannel(getter_AddRefs(channel), uri, ios, loadGroup, nsnull,
         384               0 :                          flags, channelPolicy);
         385               0 :       NS_ENSURE_SUCCESS(rv, rv);
         386                 :
         387               0 :       rv = channel->AsyncOpen(loader, indexSupports);
         388               0 :       NS_ENSURE_SUCCESS(rv, rv);
         389                 :
         390               0 :       loadInfo.mChannel.swap(channel);
         391                 :     }
         392                 :
         393               0 :     return NS_OK;
         394                 :   }
         395                 :
         396                 :   nsresult
         397               0 :   OnStreamCompleteInternal(nsIStreamLoader* aLoader, nsISupports* aContext,
         398                 :                            nsresult aStatus, PRUint32 aStringLen,
         399                 :                            const PRUint8* aString, ScriptLoadInfo& aLoadInfo)
         400                 :   {
         401               0 :     AssertIsOnMainThread();
         402                 :
         403               0 :     if (!aLoadInfo.mChannel) {
         404               0 :       return NS_BINDING_ABORTED;
         405                 :     }
         406                 :
         407               0 :     aLoadInfo.mChannel = nsnull;
         408                 :
         409               0 :     if (NS_FAILED(aStatus)) {
         410               0 :       return aStatus;
         411                 :     }
         412                 :
         413               0 :     if (!aStringLen) {
         414               0 :       return NS_OK;
         415                 :     }
         416                 :
         417               0 :     NS_ASSERTION(aString, "This should never be null!");
         418                 :
         419                 :     // Make sure we're not seeing the result of a 404 or something by checking
         420                 :     // the 'requestSucceeded' attribute on the http channel.
         421               0 :     nsCOMPtr<nsIRequest> request;
         422               0 :     nsresult rv = aLoader->GetRequest(getter_AddRefs(request));
         423               0 :     NS_ENSURE_SUCCESS(rv, rv);
         424                 :
         425               0 :     nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(request);
         426               0 :     if (httpChannel) {
         427                 :       bool requestSucceeded;
         428               0 :       rv = httpChannel->GetRequestSucceeded(&requestSucceeded);
         429               0 :       NS_ENSURE_SUCCESS(rv, rv);
         430                 :
         431               0 :       if (!requestSucceeded) {
         432               0 :         return NS_ERROR_NOT_AVAILABLE;
         433                 :       }
         434                 :     }
         435                 :
         436                 :     // May be null.
         437               0 :     nsIDocument* parentDoc = mWorkerPrivate->GetDocument();
         438                 :
         439                 :     // Use the regular nsScriptLoader for this grunt work! Should be just fine
         440                 :     // because we're running on the main thread.
         441                 :     rv = nsScriptLoader::ConvertToUTF16(aLoadInfo.mChannel, aString, aStringLen,
         442               0 :                                         EmptyString(), parentDoc,
         443               0 :                                         aLoadInfo.mScriptText);
         444               0 :     if (NS_FAILED(rv)) {
         445               0 :       return rv;
         446                 :     }
         447                 :
         448               0 :     if (aLoadInfo.mScriptText.IsEmpty()) {
         449               0 :       return NS_ERROR_FAILURE;
         450                 :     }
         451                 :
         452               0 :     nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
         453               0 :     NS_ASSERTION(channel, "This should never fail!");
         454                 :
         455                 :     // Figure out what we actually loaded.
         456               0 :     nsCOMPtr<nsIURI> finalURI;
         457               0 :     rv = NS_GetFinalChannelURI(channel, getter_AddRefs(finalURI));
         458               0 :     NS_ENSURE_SUCCESS(rv, rv);
         459                 :
         460               0 :     nsCString filename;
         461               0 :     rv = finalURI->GetSpec(filename);
         462               0 :     NS_ENSURE_SUCCESS(rv, rv);
         463                 :
         464               0 :     if (!filename.IsEmpty()) {
         465                 :       // This will help callers figure out what their script url resolved to in
         466                 :       // case of errors.
         467               0 :       aLoadInfo.mURL.Assign(NS_ConvertUTF8toUTF16(filename));
         468                 :     }
         469                 :
         470                 :     // Update the principal of the worker and its base URI if we just loaded the
         471                 :     // worker's primary script.
         472               0 :     if (mIsWorkerScript) {
         473                 :       // Take care of the base URI first.
         474               0 :       mWorkerPrivate->SetBaseURI(finalURI);
         475                 :
         476                 :       // Now to figure out which principal to give this worker.
         477               0 :       WorkerPrivate* parent = mWorkerPrivate->GetParent();
         478                 :
         479               0 :       NS_ASSERTION(mWorkerPrivate->GetPrincipal() || parent,
         480                 :                    "Must have one of these!");
         481                 :
         482               0 :       nsCOMPtr<nsIPrincipal> loadPrincipal = mWorkerPrivate->GetPrincipal() ?
         483               0 :                                              mWorkerPrivate->GetPrincipal() :
         484               0 :                                              parent->GetPrincipal();
         485                 :
         486               0 :       nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
         487               0 :       NS_ASSERTION(ssm, "Should never be null!");
         488                 :
         489               0 :       nsCOMPtr<nsIPrincipal> channelPrincipal;
         490               0 :       rv = ssm->GetChannelPrincipal(channel, getter_AddRefs(channelPrincipal));
         491               0 :       NS_ENSURE_SUCCESS(rv, rv);
         492                 :
         493                 :       // See if this is a resource URI. Since JSMs usually come from resource://
         494                 :       // URIs we're currently considering all URIs with the URI_IS_UI_RESOURCE
         495                 :       // flag as valid for creating privileged workers.
         496               0 :       if (!nsContentUtils::IsSystemPrincipal(channelPrincipal)) {
         497                 :         bool isResource;
         498                 :         rv = NS_URIChainHasFlags(finalURI,
         499                 :                                  nsIProtocolHandler::URI_IS_UI_RESOURCE,
         500               0 :                                  &isResource);
         501               0 :         NS_ENSURE_SUCCESS(rv, rv);
         502                 :
         503               0 :         if (isResource) {
         504               0 :           rv = ssm->GetSystemPrincipal(getter_AddRefs(channelPrincipal));
         505               0 :           NS_ENSURE_SUCCESS(rv, rv);
         506                 :         }
         507                 :       }
         508                 :
         509                 :       // If the load principal is the system principal then the channel
         510                 :       // principal must also be the system principal (we do not allow chrome
         511                 :       // code to create workers with non-chrome scripts). Otherwise this channel
         512                 :       // principal must be same origin with the load principal (we check again
         513                 :       // here in case redirects changed the location of the script).
         514               0 :       if (nsContentUtils::IsSystemPrincipal(loadPrincipal)) {
         515               0 :         if (!nsContentUtils::IsSystemPrincipal(channelPrincipal)) {
         516               0 :           return NS_ERROR_DOM_BAD_URI;
         517                 :         }
         518                 :       }
         519                 :       else  {
         520               0 :         nsCString scheme;
         521               0 :         rv = finalURI->GetScheme(scheme);
         522               0 :         NS_ENSURE_SUCCESS(rv, rv);
         523                 :
         524                 :         // We exempt data urls again.
         525               0 :         if (!scheme.EqualsLiteral("data") &&
         526               0 :             NS_FAILED(loadPrincipal->CheckMayLoad(finalURI, false))) {
         527               0 :           return NS_ERROR_DOM_BAD_URI;
         528                 :         }
         529                 :       }
         530                 :
         531               0 :       mWorkerPrivate->SetPrincipal(channelPrincipal);
         532                 :     }
         533                 :
         534               0 :     return NS_OK;
         535                 :   }
         536                 :
         537                 :   void
         538               0 :   ExecuteFinishedScripts()
         539                 :   {
         540               0 :     PRUint32 firstIndex = PR_UINT32_MAX;
         541               0 :     PRUint32 lastIndex = PR_UINT32_MAX;
         542                 :
         543                 :     // Find firstIndex based on whether mExecutionScheduled is unset.
         544               0 :     for (PRUint32 index = 0; index < mLoadInfos.Length(); index++) {
         545               0 :       if (!mLoadInfos[index].mExecutionScheduled) {
         546               0 :         firstIndex = index;
         547               0 :         break;
         548                 :       }
         549                 :     }
         550                 :
         551                 :     // Find lastIndex based on whether mChannel is set, and update
         552                 :     // mExecutionScheduled on the ones we're about to schedule.
         553               0 :     if (firstIndex != PR_UINT32_MAX) {
         554               0 :       for (PRUint32 index = firstIndex; index < mLoadInfos.Length(); index++) {
         555               0 :         ScriptLoadInfo& loadInfo = mLoadInfos[index];
         556                 :
         557                 :         // If we still have a channel then the load is not complete.
         558               0 :         if (loadInfo.mChannel) {
         559               0 :           break;
         560                 :         }
         561                 :
         562                 :         // We can execute this one.
         563               0 :         loadInfo.mExecutionScheduled = true;
         564                 :
         565               0 :         lastIndex = index;
         566                 :       }
         567                 :     }
         568                 :
         569               0 :     if (firstIndex != PR_UINT32_MAX && lastIndex != PR_UINT32_MAX) {
         570                 :       nsRefPtr<ScriptExecutorRunnable> runnable =
         571               0 :         new ScriptExecutorRunnable(*this, mSyncQueueKey, firstIndex, lastIndex);
         572               0 :       if (!runnable->Dispatch(nsnull)) {
         573               0 :         NS_ERROR("This should never fail!");
         574                 :       }
         575                 :     }
         576               0 :   }
         577                 : };
         578                 :
         579               0 : NS_IMPL_THREADSAFE_ISUPPORTS2(ScriptLoaderRunnable, nsIRunnable,
         580                 :                                                     nsIStreamLoaderObserver)
         581                 :
         582               0 : ScriptExecutorRunnable::ScriptExecutorRunnable(
         583                 :                                             ScriptLoaderRunnable& aScriptLoader,
         584                 :                                             PRUint32 aSyncQueueKey,
         585                 :                                             PRUint32 aFirstIndex,
         586                 :                                             PRUint32 aLastIndex)
         587                 : : WorkerSyncRunnable(aScriptLoader.mWorkerPrivate, aSyncQueueKey),
         588               0 :   mScriptLoader(aScriptLoader), mFirstIndex(aFirstIndex), mLastIndex(aLastIndex)
         589                 : {
         590               0 :   NS_ASSERTION(aFirstIndex <= aLastIndex, "Bad first index!");
         591               0 :   NS_ASSERTION(aLastIndex < aScriptLoader.mLoadInfos.Length(),
         592                 :                "Bad last index!");
         593               0 : }
         594                 :
         595                 : bool
         596               0 : ScriptExecutorRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
         597                 : {
         598               0 :   nsTArray<ScriptLoadInfo>& loadInfos = mScriptLoader.mLoadInfos;
         599                 :
         600                 :   // Don't run if something else has already failed.
         601               0 :   for (PRUint32 index = 0; index < mFirstIndex; index++) {
         602               0 :     ScriptLoadInfo& loadInfo = loadInfos.ElementAt(index);
         603                 :
         604               0 :     NS_ASSERTION(!loadInfo.mChannel, "Should no longer have a channel!");
         605               0 :     NS_ASSERTION(loadInfo.mExecutionScheduled, "Should be scheduled!");
         606                 :
         607               0 :     if (!loadInfo.mExecutionResult) {
         608               0 :       return true;
         609                 :     }
         610                 :   }
         611                 :
         612               0 :   JSObject* global = JS_GetGlobalObject(aCx);
         613               0 :   NS_ASSERTION(global, "Must have a global by now!");
         614                 :
         615               0 :   JSPrincipals* principal = GetWorkerPrincipal();
         616               0 :   NS_ASSERTION(principal, "This should never be null!");
         617                 :
         618               0 :   for (PRUint32 index = mFirstIndex; index <= mLastIndex; index++) {
         619               0 :     ScriptLoadInfo& loadInfo = loadInfos.ElementAt(index);
         620                 :
         621               0 :     NS_ASSERTION(!loadInfo.mChannel, "Should no longer have a channel!");
         622               0 :     NS_ASSERTION(loadInfo.mExecutionScheduled, "Should be scheduled!");
         623               0 :     NS_ASSERTION(!loadInfo.mExecutionResult, "Should not have executed yet!");
         624                 :
         625               0 :     if (NS_FAILED(loadInfo.mLoadResult)) {
         626               0 :       NS_ConvertUTF16toUTF8 url(loadInfo.mURL);
         627                 :
         628               0 :       switch (loadInfo.mLoadResult) {
         629                 :         case NS_BINDING_ABORTED:
         630                 :           // Canceled, don't set an exception.
         631               0 :           break;
         632                 :
         633                 :         case NS_ERROR_MALFORMED_URI:
         634               0 :           JS_ReportError(aCx, "Malformed script URI: %s", url.get());
         635               0 :           break;
         636                 :
         637                 :         case NS_ERROR_FILE_NOT_FOUND:
         638                 :         case NS_ERROR_NOT_AVAILABLE:
         639               0 :           JS_ReportError(aCx, "Script file not found: %s", url.get());
         640               0 :           break;
         641                 :
         642                 :         default:
         643                 :           JS_ReportError(aCx, "Failed to load script: %s (nsresult = 0x%x)",
         644               0 :                          url.get(), loadInfo.mLoadResult);
         645                 :       }
         646               0 :       return true;
         647                 :     }
         648                 :
         649               0 :     NS_ConvertUTF16toUTF8 filename(loadInfo.mURL);
         650                 :
         651               0 :     if (!JS_EvaluateUCScriptForPrincipals(aCx, global, principal,
         652                 :                                           loadInfo.mScriptText.get(),
         653                 :                                           loadInfo.mScriptText.Length(),
         654               0 :                                           filename.get(), 1, nsnull)) {
         655               0 :       return true;
         656                 :     }
         657                 :
         658               0 :     loadInfo.mExecutionResult = true;
         659                 :   }
         660                 :
         661               0 :   return true;
         662                 : }
         663                 :
         664                 : void
         665               0 : ScriptExecutorRunnable::PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
         666                 :                                 bool aRunResult)
         667                 : {
         668               0 :   nsTArray<ScriptLoadInfo>& loadInfos = mScriptLoader.mLoadInfos;
         669                 :
         670               0 :   if (mLastIndex == loadInfos.Length() - 1) {
         671                 :     // All done. If anything failed then return false.
         672               0 :     bool result = true;
         673               0 :     for (PRUint32 index = 0; index < loadInfos.Length(); index++) {
         674               0 :       if (!loadInfos[index].mExecutionResult) {
         675               0 :         result = false;
         676               0 :         break;
         677                 :       }
         678                 :     }
         679                 :
         680               0 :     aWorkerPrivate->RemoveFeature(aCx, &mScriptLoader);
         681               0 :     aWorkerPrivate->StopSyncLoop(mSyncQueueKey, result);
         682                 :   }
         683               0 : }
         684                 :
         685                 : bool
         686               0 : LoadAllScripts(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
         687                 :                nsTArray<ScriptLoadInfo>& aLoadInfos, bool aIsWorkerScript)
         688                 : {
         689               0 :   aWorkerPrivate->AssertIsOnWorkerThread();
         690               0 :   NS_ASSERTION(!aLoadInfos.IsEmpty(), "Bad arguments!");
         691                 :
         692               0 :   PRUint32 syncQueueKey = aWorkerPrivate->CreateNewSyncLoop();
         693                 :
         694                 :   nsRefPtr<ScriptLoaderRunnable> loader =
         695                 :     new ScriptLoaderRunnable(aWorkerPrivate, syncQueueKey, aLoadInfos,
         696               0 :                              aIsWorkerScript);
         697                 :
         698               0 :   NS_ASSERTION(aLoadInfos.IsEmpty(), "Should have swapped!");
         699                 :
         700               0 :   if (!aWorkerPrivate->AddFeature(aCx, loader)) {
         701               0 :     return false;
         702                 :   }
         703                 :
         704               0 :   if (NS_FAILED(NS_DispatchToMainThread(loader, NS_DISPATCH_NORMAL))) {
         705               0 :     NS_ERROR("Failed to dispatch!");
         706                 :
         707               0 :     aWorkerPrivate->RemoveFeature(aCx, loader);
         708               0 :     return false;
         709                 :   }
         710                 :
         711               0 :   return aWorkerPrivate->RunSyncLoop(aCx, syncQueueKey);
         712                 : }
         713                 :
         714                 : } /* anonymous namespace */
         715                 :
         716                 : BEGIN_WORKERS_NAMESPACE
         717                 :
         718                 : namespace scriptloader {
         719                 :
         720                 : bool
         721               0 : LoadWorkerScript(JSContext* aCx)
         722                 : {
         723               0 :   WorkerPrivate* worker = GetWorkerPrivateFromContext(aCx);
         724               0 :   NS_ASSERTION(worker, "This should never be null!");
         725                 :
         726               0 :   nsTArray<ScriptLoadInfo> loadInfos;
         727                 :
         728               0 :   ScriptLoadInfo* info = loadInfos.AppendElement();
         729               0 :   info->mURL = worker->ScriptURL();
         730                 :
         731               0 :   return LoadAllScripts(aCx, worker, loadInfos, true);
         732                 : }
         733                 :
         734                 : bool
         735               0 : Load(JSContext* aCx, unsigned aURLCount, jsval* aURLs)
         736                 : {
         737               0 :   WorkerPrivate* worker = GetWorkerPrivateFromContext(aCx);
         738               0 :   NS_ASSERTION(worker, "This should never be null!");
         739                 :
         740               0 :   if (!aURLCount) {
         741               0 :     return true;
         742                 :   }
         743                 :
         744               0 :   if (aURLCount > MAX_CONCURRENT_SCRIPTS) {
         745                 :     JS_ReportError(aCx, "Cannot load more than %d scripts at one time!",
         746               0 :                    MAX_CONCURRENT_SCRIPTS);
         747               0 :     return false;
         748                 :   }
         749                 :
         750               0 :   nsTArray<ScriptLoadInfo> loadInfos;
         751               0 :   loadInfos.SetLength(PRUint32(aURLCount));
         752                 :
         753               0 :   for (unsigned index = 0; index < aURLCount; index++) {
         754               0 :     JSString* str = JS_ValueToString(aCx, aURLs[index]);
         755               0 :     if (!str) {
         756               0 :       return false;
         757                 :     }
         758                 :
         759                 :     size_t length;
         760               0 :     const jschar* buffer = JS_GetStringCharsAndLength(aCx, str, &length);
         761               0 :     if (!buffer) {
         762               0 :       return false;
         763                 :     }
         764                 :
         765               0 :     loadInfos[index].mURL.Assign(buffer, length);
         766                 :   }
         767                 :
         768               0 :   return LoadAllScripts(aCx, worker, loadInfos, false);
         769                 : }
         770                 :
         771                 : } // namespace scriptloader
         772                 :
         773                 : END_WORKERS_NAMESPACE

Generated by: LCOV version 1.7