LCOV - code coverage report
Current view: directory - content/base/src - nsScriptLoader.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 613 48 7.8 %
Date: 2012-06-02 Functions: 40 9 22.5 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : // vim: ft=cpp tw=78 sw=2 et ts=2
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is Mozilla.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Netscape Communications.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 2001
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   Vidur Apparao <vidur@netscape.com> (original author)
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      28                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : /*
      41                 :  * A class that handles loading and evaluation of <script> elements.
      42                 :  */
      43                 : 
      44                 : #include "jsapi.h"
      45                 : #include "jsfriendapi.h"
      46                 : #include "nsScriptLoader.h"
      47                 : #include "nsICharsetConverterManager.h"
      48                 : #include "nsIUnicodeDecoder.h"
      49                 : #include "nsIContent.h"
      50                 : #include "mozilla/dom/Element.h"
      51                 : #include "nsGkAtoms.h"
      52                 : #include "nsNetUtil.h"
      53                 : #include "nsIScriptGlobalObject.h"
      54                 : #include "nsIScriptContext.h"
      55                 : #include "nsIScriptRuntime.h"
      56                 : #include "nsIScriptSecurityManager.h"
      57                 : #include "nsIPrincipal.h"
      58                 : #include "nsContentPolicyUtils.h"
      59                 : #include "nsIHttpChannel.h"
      60                 : #include "nsIScriptElement.h"
      61                 : #include "nsIDOMHTMLScriptElement.h"
      62                 : #include "nsIDocShell.h"
      63                 : #include "nsContentUtils.h"
      64                 : #include "nsUnicharUtils.h"
      65                 : #include "nsAutoPtr.h"
      66                 : #include "nsIXPConnect.h"
      67                 : #include "nsContentErrors.h"
      68                 : #include "nsIParser.h"
      69                 : #include "nsThreadUtils.h"
      70                 : #include "nsDocShellCID.h"
      71                 : #include "nsIContentSecurityPolicy.h"
      72                 : #include "prlog.h"
      73                 : #include "nsIChannelPolicy.h"
      74                 : #include "nsChannelPolicy.h"
      75                 : #include "nsCRT.h"
      76                 : #include "nsContentCreatorFunctions.h"
      77                 : #include "nsGenericElement.h"
      78                 : #include "nsCrossSiteListenerProxy.h"
      79                 : 
      80                 : #include "mozilla/FunctionTimer.h"
      81                 : #include "mozilla/CORSMode.h"
      82                 : 
      83                 : #ifdef PR_LOGGING
      84                 : static PRLogModuleInfo* gCspPRLog;
      85                 : #endif
      86                 : 
      87                 : using namespace mozilla;
      88                 : using namespace mozilla::dom;
      89                 : 
      90                 : //////////////////////////////////////////////////////////////
      91                 : // Per-request data structure
      92                 : //////////////////////////////////////////////////////////////
      93                 : 
      94               0 : class nsScriptLoadRequest : public nsISupports {
      95                 : public:
      96               0 :   nsScriptLoadRequest(nsIScriptElement* aElement,
      97                 :                       PRUint32 aVersion,
      98                 :                       CORSMode aCORSMode)
      99                 :     : mElement(aElement),
     100                 :       mLoading(true),
     101                 :       mIsInline(true),
     102                 :       mJSVersion(aVersion),
     103                 :       mLineNo(1),
     104               0 :       mCORSMode(aCORSMode)
     105                 :   {
     106               0 :   }
     107                 : 
     108                 :   NS_DECL_ISUPPORTS
     109                 : 
     110               0 :   void FireScriptAvailable(nsresult aResult)
     111                 :   {
     112               0 :     mElement->ScriptAvailable(aResult, mElement, mIsInline, mURI, mLineNo);
     113               0 :   }
     114               0 :   void FireScriptEvaluated(nsresult aResult)
     115                 :   {
     116               0 :     mElement->ScriptEvaluated(aResult, mElement, mIsInline);
     117               0 :   }
     118                 : 
     119               0 :   bool IsPreload()
     120                 :   {
     121               0 :     return mElement == nsnull;
     122                 :   }
     123                 : 
     124                 :   nsCOMPtr<nsIScriptElement> mElement;
     125                 :   bool mLoading;             // Are we still waiting for a load to complete?
     126                 :   bool mIsInline;            // Is the script inline or loaded?
     127                 :   nsString mScriptText;              // Holds script for loaded scripts
     128                 :   PRUint32 mJSVersion;
     129                 :   nsCOMPtr<nsIURI> mURI;
     130                 :   nsCOMPtr<nsIPrincipal> mOriginPrincipal;
     131                 :   PRInt32 mLineNo;
     132                 :   const CORSMode mCORSMode;
     133                 : };
     134                 : 
     135                 : // The nsScriptLoadRequest is passed as the context to necko, and thus
     136                 : // it needs to be threadsafe. Necko won't do anything with this
     137                 : // context, but it will AddRef and Release it on other threads.
     138               0 : NS_IMPL_THREADSAFE_ISUPPORTS0(nsScriptLoadRequest)
     139                 : 
     140                 : //////////////////////////////////////////////////////////////
     141                 : //
     142                 : //////////////////////////////////////////////////////////////
     143                 : 
     144            1273 : nsScriptLoader::nsScriptLoader(nsIDocument *aDocument)
     145                 :   : mDocument(aDocument),
     146                 :     mBlockerCount(0),
     147                 :     mEnabled(true),
     148                 :     mDeferEnabled(false),
     149            1273 :     mDocumentParsingDone(false)
     150                 : {
     151                 :   // enable logging for CSP
     152                 : #ifdef PR_LOGGING
     153            1273 :   if (!gCspPRLog)
     154             249 :     gCspPRLog = PR_NewLogModule("CSP");
     155                 : #endif
     156            1273 : }
     157                 : 
     158            3813 : nsScriptLoader::~nsScriptLoader()
     159                 : {
     160            1271 :   mObservers.Clear();
     161                 : 
     162            1271 :   if (mParserBlockingRequest) {
     163               0 :     mParserBlockingRequest->FireScriptAvailable(NS_ERROR_ABORT);
     164                 :   }
     165                 : 
     166            1271 :   for (PRUint32 i = 0; i < mXSLTRequests.Length(); i++) {
     167               0 :     mXSLTRequests[i]->FireScriptAvailable(NS_ERROR_ABORT);
     168                 :   }
     169                 : 
     170            1271 :   for (PRUint32 i = 0; i < mDeferRequests.Length(); i++) {
     171               0 :     mDeferRequests[i]->FireScriptAvailable(NS_ERROR_ABORT);
     172                 :   }
     173                 : 
     174            1271 :   for (PRUint32 i = 0; i < mAsyncRequests.Length(); i++) {
     175               0 :     mAsyncRequests[i]->FireScriptAvailable(NS_ERROR_ABORT);
     176                 :   }
     177                 : 
     178            1271 :   for (PRUint32 i = 0; i < mNonAsyncExternalScriptInsertedRequests.Length(); i++) {
     179               0 :     mNonAsyncExternalScriptInsertedRequests[i]->FireScriptAvailable(NS_ERROR_ABORT);
     180                 :   }
     181                 : 
     182                 :   // Unblock the kids, in case any of them moved to a different document
     183                 :   // subtree in the meantime and therefore aren't actually going away.
     184            1271 :   for (PRUint32 j = 0; j < mPendingChildLoaders.Length(); ++j) {
     185               0 :     mPendingChildLoaders[j]->RemoveExecuteBlocker();
     186                 :   }  
     187            5084 : }
     188                 : 
     189            6552 : NS_IMPL_ISUPPORTS1(nsScriptLoader, nsIStreamLoaderObserver)
     190                 : 
     191                 : // Helper method for checking if the script element is an event-handler
     192                 : // This means that it has both a for-attribute and a event-attribute.
     193                 : // Also, if the for-attribute has a value that matches "\s*window\s*",
     194                 : // and the event-attribute matches "\s*onload([ \(].*)?" then it isn't an
     195                 : // eventhandler. (both matches are case insensitive).
     196                 : // This is how IE seems to filter out a window's onload handler from a
     197                 : // <script for=... event=...> element.
     198                 : 
     199                 : static bool
     200               0 : IsScriptEventHandler(nsIContent* aScriptElement)
     201                 : {
     202               0 :   if (!aScriptElement->IsHTML()) {
     203               0 :     return false;
     204                 :   }
     205                 : 
     206               0 :   nsAutoString forAttr, eventAttr;
     207               0 :   if (!aScriptElement->GetAttr(kNameSpaceID_None, nsGkAtoms::_for, forAttr) ||
     208               0 :       !aScriptElement->GetAttr(kNameSpaceID_None, nsGkAtoms::event, eventAttr)) {
     209               0 :     return false;
     210                 :   }
     211                 : 
     212                 :   const nsAString& for_str =
     213               0 :     nsContentUtils::TrimWhitespace<nsCRT::IsAsciiSpace>(forAttr);
     214               0 :   if (!for_str.LowerCaseEqualsLiteral("window")) {
     215               0 :     return true;
     216                 :   }
     217                 : 
     218                 :   // We found for="window", now check for event="onload".
     219                 :   const nsAString& event_str =
     220               0 :     nsContentUtils::TrimWhitespace<nsCRT::IsAsciiSpace>(eventAttr, false);
     221               0 :   if (!StringBeginsWith(event_str, NS_LITERAL_STRING("onload"),
     222               0 :                         nsCaseInsensitiveStringComparator())) {
     223                 :     // It ain't "onload.*".
     224                 : 
     225               0 :     return true;
     226                 :   }
     227                 : 
     228               0 :   nsAutoString::const_iterator start, end;
     229               0 :   event_str.BeginReading(start);
     230               0 :   event_str.EndReading(end);
     231                 : 
     232               0 :   start.advance(6); // advance past "onload"
     233                 : 
     234               0 :   if (start != end && *start != '(' && *start != ' ') {
     235                 :     // We got onload followed by something other than space or
     236                 :     // '('. Not good enough.
     237                 : 
     238               0 :     return true;
     239                 :   }
     240                 : 
     241               0 :   return false;
     242                 : }
     243                 : 
     244                 : nsresult
     245               0 : nsScriptLoader::CheckContentPolicy(nsIDocument* aDocument,
     246                 :                                    nsISupports *aContext,
     247                 :                                    nsIURI *aURI,
     248                 :                                    const nsAString &aType)
     249                 : {
     250               0 :   PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
     251                 :   nsresult rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_SCRIPT,
     252                 :                                           aURI,
     253                 :                                           aDocument->NodePrincipal(),
     254                 :                                           aContext,
     255               0 :                                           NS_LossyConvertUTF16toASCII(aType),
     256                 :                                           nsnull,    //extra
     257                 :                                           &shouldLoad,
     258                 :                                           nsContentUtils::GetContentPolicy(),
     259               0 :                                           nsContentUtils::GetSecurityManager());
     260               0 :   if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
     261               0 :     if (NS_FAILED(rv) || shouldLoad != nsIContentPolicy::REJECT_TYPE) {
     262               0 :       return NS_ERROR_CONTENT_BLOCKED;
     263                 :     }
     264               0 :     return NS_ERROR_CONTENT_BLOCKED_SHOW_ALT;
     265                 :   }
     266                 : 
     267               0 :   return NS_OK;
     268                 : }
     269                 : 
     270                 : nsresult
     271               0 : nsScriptLoader::ShouldLoadScript(nsIDocument* aDocument,
     272                 :                                  nsISupports* aContext,
     273                 :                                  nsIURI* aURI,
     274                 :                                  const nsAString &aType)
     275                 : {
     276                 :   // Check that the containing page is allowed to load this URI.
     277               0 :   nsresult rv = nsContentUtils::GetSecurityManager()->
     278                 :     CheckLoadURIWithPrincipal(aDocument->NodePrincipal(), aURI,
     279               0 :                               nsIScriptSecurityManager::ALLOW_CHROME);
     280                 : 
     281               0 :   NS_ENSURE_SUCCESS(rv, rv);
     282                 : 
     283                 :   // After the security manager, the content-policy stuff gets a veto
     284               0 :   rv = CheckContentPolicy(aDocument, aContext, aURI, aType);
     285               0 :   if (NS_FAILED(rv)) {
     286               0 :     return rv;
     287                 :   }
     288                 : 
     289               0 :   return NS_OK;
     290                 : }
     291                 : 
     292                 : nsresult
     293               0 : nsScriptLoader::StartLoad(nsScriptLoadRequest *aRequest, const nsAString &aType)
     294                 : {
     295               0 :   nsISupports *context = aRequest->mElement.get()
     296               0 :                          ? static_cast<nsISupports *>(aRequest->mElement.get())
     297               0 :                          : static_cast<nsISupports *>(mDocument);
     298               0 :   nsresult rv = ShouldLoadScript(mDocument, context, aRequest->mURI, aType);
     299               0 :   if (NS_FAILED(rv)) {
     300               0 :     return rv;
     301                 :   }
     302                 : 
     303               0 :   nsCOMPtr<nsILoadGroup> loadGroup = mDocument->GetDocumentLoadGroup();
     304                 : 
     305               0 :   nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(mDocument->GetScriptGlobalObject()));
     306               0 :   if (!window) {
     307               0 :     return NS_ERROR_NULL_POINTER;
     308                 :   }
     309                 : 
     310               0 :   nsIDocShell *docshell = window->GetDocShell();
     311                 : 
     312               0 :   nsCOMPtr<nsIInterfaceRequestor> prompter(do_QueryInterface(docshell));
     313                 : 
     314                 :   // check for a Content Security Policy to pass down to the channel
     315                 :   // that will be created to load the script
     316               0 :   nsCOMPtr<nsIChannelPolicy> channelPolicy;
     317               0 :   nsCOMPtr<nsIContentSecurityPolicy> csp;
     318               0 :   rv = mDocument->NodePrincipal()->GetCsp(getter_AddRefs(csp));
     319               0 :   NS_ENSURE_SUCCESS(rv, rv);
     320               0 :   if (csp) {
     321               0 :     channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
     322               0 :     channelPolicy->SetContentSecurityPolicy(csp);
     323               0 :     channelPolicy->SetLoadType(nsIContentPolicy::TYPE_SCRIPT);
     324                 :   }
     325                 : 
     326               0 :   nsCOMPtr<nsIChannel> channel;
     327               0 :   rv = NS_NewChannel(getter_AddRefs(channel),
     328                 :                      aRequest->mURI, nsnull, loadGroup, prompter,
     329                 :                      nsIRequest::LOAD_NORMAL | nsIChannel::LOAD_CLASSIFY_URI,
     330               0 :                      channelPolicy);
     331               0 :   NS_ENSURE_SUCCESS(rv, rv);
     332                 : 
     333               0 :   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
     334               0 :   if (httpChannel) {
     335                 :     // HTTP content negotation has little value in this context.
     336               0 :     httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
     337               0 :                                   NS_LITERAL_CSTRING("*/*"),
     338               0 :                                   false);
     339               0 :     httpChannel->SetReferrer(mDocument->GetDocumentURI());
     340                 :   }
     341                 : 
     342               0 :   nsCOMPtr<nsIStreamLoader> loader;
     343               0 :   rv = NS_NewStreamLoader(getter_AddRefs(loader), this);
     344               0 :   NS_ENSURE_SUCCESS(rv, rv);
     345                 : 
     346               0 :   nsCOMPtr<nsIStreamListener> listener = loader.get();
     347                 : 
     348               0 :   if (aRequest->mCORSMode != CORS_NONE) {
     349               0 :     bool withCredentials = (aRequest->mCORSMode == CORS_USE_CREDENTIALS);
     350                 :     listener =
     351               0 :       new nsCORSListenerProxy(listener, mDocument->NodePrincipal(), channel,
     352               0 :                               withCredentials, &rv);
     353               0 :     NS_ENSURE_SUCCESS(rv, rv);
     354                 :   }
     355                 : 
     356               0 :   rv = channel->AsyncOpen(listener, aRequest);
     357               0 :   NS_ENSURE_SUCCESS(rv, rv);
     358                 : 
     359               0 :   return NS_OK;
     360                 : }
     361                 : 
     362                 : bool
     363               0 : nsScriptLoader::PreloadURIComparator::Equals(const PreloadInfo &aPi,
     364                 :                                              nsIURI * const &aURI) const
     365                 : {
     366                 :   bool same;
     367               0 :   return NS_SUCCEEDED(aPi.mRequest->mURI->Equals(aURI, &same)) &&
     368               0 :          same;
     369                 : }
     370                 : 
     371                 : class nsScriptRequestProcessor : public nsRunnable
     372               0 : {
     373                 : private:
     374                 :   nsRefPtr<nsScriptLoader> mLoader;
     375                 :   nsRefPtr<nsScriptLoadRequest> mRequest;
     376                 : public:
     377               0 :   nsScriptRequestProcessor(nsScriptLoader* aLoader,
     378                 :                            nsScriptLoadRequest* aRequest)
     379                 :     : mLoader(aLoader)
     380               0 :     , mRequest(aRequest)
     381               0 :   {}
     382               0 :   NS_IMETHODIMP Run()
     383                 :   {
     384               0 :     return mLoader->ProcessRequest(mRequest);
     385                 :   }
     386                 : };
     387                 : 
     388                 : bool
     389               0 : nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
     390                 : {
     391                 :   // We need a document to evaluate scripts.
     392               0 :   NS_ENSURE_TRUE(mDocument, false);
     393                 : 
     394                 :   // Check to see if scripts has been turned off.
     395               0 :   if (!mEnabled || !mDocument->IsScriptEnabled()) {
     396               0 :     return false;
     397                 :   }
     398                 : 
     399               0 :   NS_ASSERTION(!aElement->IsMalformed(), "Executing malformed script");
     400                 : 
     401               0 :   nsCOMPtr<nsIContent> scriptContent = do_QueryInterface(aElement);
     402                 : 
     403                 :   // Step 12. Check that the script is not an eventhandler
     404               0 :   if (IsScriptEventHandler(scriptContent)) {
     405               0 :     return false;
     406                 :   }
     407                 : 
     408                 :   // Script evaluation can also be disabled in the current script
     409                 :   // context even though it's enabled in the document.
     410                 :   // XXX - still hard-coded for JS here, even though another language
     411                 :   // may be specified.  Should this check be made *after* we examine
     412                 :   // the attributes to locate the script-type?
     413                 :   // For now though, if JS is disabled we assume every language is
     414                 :   // disabled.
     415                 :   // XXX is this different from the mDocument->IsScriptEnabled() call?
     416               0 :   nsIScriptGlobalObject *globalObject = mDocument->GetScriptGlobalObject();
     417               0 :   if (!globalObject) {
     418               0 :     return false;
     419                 :   }
     420                 :   
     421                 :   nsIScriptContext *context = globalObject->GetScriptContext(
     422               0 :                                         nsIProgrammingLanguage::JAVASCRIPT);
     423                 : 
     424                 :   // If scripts aren't enabled in the current context, there's no
     425                 :   // point in going on.
     426               0 :   if (!context || !context->GetScriptsEnabled()) {
     427               0 :     return false;
     428                 :   }
     429                 : 
     430                 :   // Default script language is whatever the root element specifies
     431                 :   // (which may come from a header or http-meta tag), or if there
     432                 :   // is no root element, from the script global object.
     433               0 :   Element* rootElement = mDocument->GetRootElement();
     434               0 :   PRUint32 typeID = rootElement ? rootElement->GetScriptTypeID() :
     435               0 :                                   context->GetScriptTypeID();
     436               0 :   PRUint32 version = 0;
     437               0 :   nsAutoString language, type, src;
     438               0 :   nsresult rv = NS_OK;
     439                 : 
     440                 :   // Check the type attribute to determine language and version.
     441                 :   // If type exists, it trumps the deprecated 'language='
     442               0 :   aElement->GetScriptType(type);
     443               0 :   if (!type.IsEmpty()) {
     444               0 :     nsContentTypeParser parser(type);
     445                 : 
     446               0 :     nsAutoString mimeType;
     447               0 :     rv = parser.GetType(mimeType);
     448               0 :     NS_ENSURE_SUCCESS(rv, false);
     449                 : 
     450                 :     // Javascript keeps the fast path, optimized for most-likely type
     451                 :     // Table ordered from most to least likely JS MIME types.
     452                 :     // See bug 62485, feel free to add <script type="..."> survey data to it,
     453                 :     // or to a new bug once 62485 is closed.
     454                 :     static const char *jsTypes[] = {
     455                 :       "text/javascript",
     456                 :       "text/ecmascript",
     457                 :       "application/javascript",
     458                 :       "application/ecmascript",
     459                 :       "application/x-javascript",
     460                 :       nsnull
     461                 :     };
     462                 : 
     463               0 :     bool isJavaScript = false;
     464               0 :     for (PRInt32 i = 0; jsTypes[i]; i++) {
     465               0 :       if (mimeType.LowerCaseEqualsASCII(jsTypes[i])) {
     466               0 :         isJavaScript = true;
     467               0 :         break;
     468                 :       }
     469                 :     }
     470               0 :     if (isJavaScript)
     471               0 :       typeID = nsIProgrammingLanguage::JAVASCRIPT;
     472                 :     else {
     473                 :       // Use the object factory to locate a matching language.
     474               0 :       nsCOMPtr<nsIScriptRuntime> runtime;
     475               0 :       rv = NS_GetScriptRuntime(mimeType, getter_AddRefs(runtime));
     476               0 :       if (NS_FAILED(rv) || runtime == nsnull) {
     477                 :         // Failed to get the explicitly specified language
     478               0 :         NS_WARNING("Failed to find a scripting language");
     479               0 :         typeID = nsIProgrammingLanguage::UNKNOWN;
     480                 :       } else
     481               0 :         typeID = runtime->GetScriptTypeID();
     482                 :     }
     483               0 :     if (typeID != nsIProgrammingLanguage::UNKNOWN) {
     484                 :       // Get the version string, and ensure the language supports it.
     485               0 :       nsAutoString versionName;
     486               0 :       rv = parser.GetParameter("version", versionName);
     487               0 :       if (NS_FAILED(rv)) {
     488                 :         // no version attribute - version remains 0.
     489               0 :         if (rv != NS_ERROR_INVALID_ARG)
     490               0 :           return false;
     491                 :       } else {
     492               0 :         nsCOMPtr<nsIScriptRuntime> runtime;
     493               0 :         rv = NS_GetScriptRuntimeByID(typeID, getter_AddRefs(runtime));
     494               0 :         if (NS_FAILED(rv)) {
     495               0 :           NS_ERROR("Failed to locate the language with this ID");
     496               0 :           return false;
     497                 :         }
     498               0 :         rv = runtime->ParseVersion(versionName, &version);
     499               0 :         if (NS_FAILED(rv)) {
     500               0 :           NS_WARNING("This script language version is not supported - ignored");
     501               0 :           typeID = nsIProgrammingLanguage::UNKNOWN;
     502                 :         }
     503                 :       }
     504                 :     }
     505                 : 
     506                 :     // Some js specifics yet to be abstracted.
     507               0 :     if (typeID == nsIProgrammingLanguage::JAVASCRIPT) {
     508               0 :       nsAutoString value;
     509               0 :       rv = parser.GetParameter("e4x", value);
     510               0 :       if (NS_FAILED(rv)) {
     511               0 :         if (rv != NS_ERROR_INVALID_ARG)
     512               0 :           return false;
     513                 :       } else {
     514               0 :         if (value.Length() == 1 && value[0] == '1')
     515                 :           // This means that we need to set JSOPTION_XML in the JS options.
     516                 :           // We re-use our knowledge of the implementation to reuse
     517                 :           // JSVERSION_HAS_XML as a safe version flag.
     518                 :           // If version has JSVERSION_UNKNOWN (-1), then this is still OK.
     519               0 :           version = js::VersionSetXML(JSVersion(version), true);
     520                 :       }
     521                 :     }
     522                 :   } else {
     523                 :     // no 'type=' element
     524                 :     // "language" is a deprecated attribute of HTML, so we check it only for
     525                 :     // HTML script elements.
     526               0 :     if (scriptContent->IsHTML()) {
     527               0 :       scriptContent->GetAttr(kNameSpaceID_None, nsGkAtoms::language, language);
     528               0 :       if (!language.IsEmpty()) {
     529               0 :         if (nsContentUtils::IsJavaScriptLanguage(language, &version))
     530               0 :           typeID = nsIProgrammingLanguage::JAVASCRIPT;
     531                 :         else
     532               0 :           typeID = nsIProgrammingLanguage::UNKNOWN;
     533                 :         // IE, Opera, etc. do not respect language version, so neither should
     534                 :         // we at this late date in the browser wars saga.  Note that this change
     535                 :         // affects HTML but not XUL or SVG (but note also that XUL has its own
     536                 :         // code to check nsContentUtils::IsJavaScriptLanguage -- that's probably
     537                 :         // a separate bug, one we may not be able to fix short of XUL2).  See
     538                 :         // bug 255895 (https://bugzilla.mozilla.org/show_bug.cgi?id=255895).
     539                 :         NS_ASSERTION(JSVERSION_DEFAULT == 0,
     540                 :                      "We rely on all languages having 0 as a version default");
     541               0 :         version = 0;
     542                 :       }
     543                 :     }
     544                 :   }
     545                 : 
     546                 :   // If we don't know the language, we don't know how to evaluate
     547               0 :   if (typeID == nsIProgrammingLanguage::UNKNOWN) {
     548               0 :     return false;
     549                 :   }
     550                 :   // If not from a chrome document (which is always trusted), we need some way 
     551                 :   // of checking the language is "safe".  Currently the only other language 
     552                 :   // impl is Python, and that is *not* safe in untrusted code - so fixing 
     553                 :   // this isn't a priority.!
     554                 :   // See also similar code in nsXULContentSink.cpp
     555               0 :   if (typeID != nsIProgrammingLanguage::JAVASCRIPT &&
     556               0 :       !nsContentUtils::IsChromeDoc(mDocument)) {
     557               0 :     NS_WARNING("Untrusted language called from non-chrome - ignored");
     558               0 :     return false;
     559                 :   }
     560                 : 
     561               0 :   scriptContent->SetScriptTypeID(typeID);
     562                 : 
     563                 :   // Step 14. in the HTML5 spec
     564                 : 
     565               0 :   nsRefPtr<nsScriptLoadRequest> request;
     566               0 :   if (aElement->GetScriptExternal()) {
     567                 :     // external script
     568               0 :     nsCOMPtr<nsIURI> scriptURI = aElement->GetScriptURI();
     569               0 :     if (!scriptURI) {
     570               0 :       return false;
     571                 :     }
     572               0 :     CORSMode ourCORSMode = aElement->GetCORSMode();
     573                 :     nsTArray<PreloadInfo>::index_type i =
     574               0 :       mPreloads.IndexOf(scriptURI.get(), 0, PreloadURIComparator());
     575               0 :     if (i != nsTArray<PreloadInfo>::NoIndex) {
     576                 :       // preloaded
     577                 :       // note that a script-inserted script can steal a preload!
     578               0 :       request = mPreloads[i].mRequest;
     579               0 :       request->mElement = aElement;
     580               0 :       nsString preloadCharset(mPreloads[i].mCharset);
     581               0 :       mPreloads.RemoveElementAt(i);
     582                 : 
     583                 :       // Double-check that the charset the preload used is the same as
     584                 :       // the charset we have now.
     585               0 :       nsAutoString elementCharset;
     586               0 :       aElement->GetScriptCharset(elementCharset);
     587               0 :       if (elementCharset.Equals(preloadCharset) &&
     588               0 :           ourCORSMode == request->mCORSMode) {
     589               0 :         rv = CheckContentPolicy(mDocument, aElement, request->mURI, type);
     590               0 :         NS_ENSURE_SUCCESS(rv, false);
     591                 :       } else {
     592                 :         // Drop the preload
     593               0 :         request = nsnull;
     594                 :       }
     595                 :     }
     596                 : 
     597               0 :     if (!request) {
     598                 :       // no usable preload
     599               0 :       request = new nsScriptLoadRequest(aElement, version, ourCORSMode);
     600               0 :       request->mURI = scriptURI;
     601               0 :       request->mIsInline = false;
     602               0 :       request->mLoading = true;
     603               0 :       rv = StartLoad(request, type);
     604               0 :       NS_ENSURE_SUCCESS(rv, false);
     605                 :     }
     606                 : 
     607               0 :     request->mJSVersion = version;
     608                 : 
     609               0 :     if (aElement->GetScriptAsync()) {
     610               0 :       mAsyncRequests.AppendElement(request);
     611               0 :       if (!request->mLoading) {
     612                 :         // The script is available already. Run it ASAP when the event
     613                 :         // loop gets a chance to spin.
     614               0 :         ProcessPendingRequestsAsync();
     615                 :       }
     616               0 :       return false;
     617                 :     }
     618               0 :     if (!aElement->GetParserCreated()) {
     619                 :       // Violate the HTML5 spec in order to make LABjs and the "order" plug-in
     620                 :       // for RequireJS work with their Gecko-sniffed code path. See
     621                 :       // http://lists.w3.org/Archives/Public/public-html/2010Oct/0088.html
     622               0 :       mNonAsyncExternalScriptInsertedRequests.AppendElement(request);
     623               0 :       if (!request->mLoading) {
     624                 :         // The script is available already. Run it ASAP when the event
     625                 :         // loop gets a chance to spin.
     626               0 :         ProcessPendingRequestsAsync();
     627                 :       }
     628               0 :       return false;
     629                 :     }
     630                 :     // we now have a parser-inserted request that may or may not be still
     631                 :     // loading
     632               0 :     if (aElement->GetScriptDeferred()) {
     633                 :       // We don't want to run this yet.
     634                 :       // If we come here, the script is a parser-created script and it has
     635                 :       // the defer attribute but not the async attribute. Since a
     636                 :       // a parser-inserted script is being run, we came here by the parser
     637                 :       // running the script, which means the parser is still alive and the
     638                 :       // parse is ongoing.
     639               0 :       NS_ASSERTION(mDocument->GetCurrentContentSink() ||
     640                 :                    aElement->GetParserCreated() == FROM_PARSER_XSLT,
     641                 :           "Non-XSLT Defer script on a document without an active parser; bug 592366.");
     642               0 :       mDeferRequests.AppendElement(request);
     643               0 :       return false;
     644                 :     }
     645                 : 
     646               0 :     if (aElement->GetParserCreated() == FROM_PARSER_XSLT) {
     647                 :       // Need to maintain order for XSLT-inserted scripts
     648               0 :       NS_ASSERTION(!mParserBlockingRequest,
     649                 :           "Parser-blocking scripts and XSLT scripts in the same doc!");
     650               0 :       mXSLTRequests.AppendElement(request);
     651               0 :       if (!request->mLoading) {
     652                 :         // The script is available already. Run it ASAP when the event
     653                 :         // loop gets a chance to spin.
     654               0 :         ProcessPendingRequestsAsync();
     655                 :       }
     656               0 :       return true;
     657                 :     }
     658               0 :     if (!request->mLoading && ReadyToExecuteScripts()) {
     659                 :       // The request has already been loaded and there are no pending style
     660                 :       // sheets. If the script comes from the network stream, cheat for
     661                 :       // performance reasons and avoid a trip through the event loop.
     662               0 :       if (aElement->GetParserCreated() == FROM_PARSER_NETWORK) {
     663               0 :         return ProcessRequest(request) == NS_ERROR_HTMLPARSER_BLOCK;
     664                 :       }
     665                 :       // Otherwise, we've got a document.written script, make a trip through
     666                 :       // the event loop to hide the preload effects from the scripts on the
     667                 :       // Web page.
     668               0 :       NS_ASSERTION(!mParserBlockingRequest,
     669                 :           "There can be only one parser-blocking script at a time");
     670               0 :       NS_ASSERTION(mXSLTRequests.IsEmpty(),
     671                 :           "Parser-blocking scripts and XSLT scripts in the same doc!");
     672               0 :       mParserBlockingRequest = request;
     673               0 :       ProcessPendingRequestsAsync();
     674               0 :       return true;
     675                 :     }
     676                 :     // The script hasn't loaded yet or there's a style sheet blocking it.
     677                 :     // The script will be run when it loads or the style sheet loads.
     678               0 :     NS_ASSERTION(!mParserBlockingRequest,
     679                 :         "There can be only one parser-blocking script at a time");
     680               0 :     NS_ASSERTION(mXSLTRequests.IsEmpty(),
     681                 :         "Parser-blocking scripts and XSLT scripts in the same doc!");
     682               0 :     mParserBlockingRequest = request;
     683               0 :     return true;
     684                 :   }
     685                 : 
     686                 :   // inline script
     687               0 :   nsCOMPtr<nsIContentSecurityPolicy> csp;
     688               0 :   rv = mDocument->NodePrincipal()->GetCsp(getter_AddRefs(csp));
     689               0 :   NS_ENSURE_SUCCESS(rv, false);
     690                 : 
     691               0 :   if (csp) {
     692               0 :     PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("New ScriptLoader i ****with CSP****"));
     693                 :     bool inlineOK;
     694               0 :     rv = csp->GetAllowsInlineScript(&inlineOK);
     695               0 :     NS_ENSURE_SUCCESS(rv, false);
     696                 : 
     697               0 :     if (!inlineOK) {
     698               0 :       PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("CSP blocked inline scripts (2)"));
     699                 :       // gather information to log with violation report
     700               0 :       nsIURI* uri = mDocument->GetDocumentURI();
     701               0 :       nsCAutoString asciiSpec;
     702               0 :       uri->GetAsciiSpec(asciiSpec);
     703               0 :       nsAutoString scriptText;
     704               0 :       aElement->GetScriptText(scriptText);
     705                 : 
     706                 :       // cap the length of the script sample at 40 chars
     707               0 :       if (scriptText.Length() > 40) {
     708               0 :         scriptText.Truncate(40);
     709               0 :         scriptText.Append(NS_LITERAL_STRING("..."));
     710                 :       }
     711                 : 
     712               0 :       csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_INLINE_SCRIPT,
     713               0 :                                NS_ConvertUTF8toUTF16(asciiSpec),
     714                 :                                scriptText,
     715               0 :                                aElement->GetScriptLineNumber());
     716               0 :       return false;
     717                 :     }
     718                 :   }
     719                 : 
     720                 :   // Inline scripts ignore ther CORS mode and are always CORS_NONE
     721               0 :   request = new nsScriptLoadRequest(aElement, version, CORS_NONE);
     722               0 :   request->mJSVersion = version;
     723               0 :   request->mLoading = false;
     724               0 :   request->mIsInline = true;
     725               0 :   request->mURI = mDocument->GetDocumentURI();
     726               0 :   request->mLineNo = aElement->GetScriptLineNumber();
     727                 : 
     728               0 :   if (aElement->GetParserCreated() == FROM_PARSER_XSLT &&
     729               0 :       (!ReadyToExecuteScripts() || !mXSLTRequests.IsEmpty())) {
     730                 :     // Need to maintain order for XSLT-inserted scripts
     731               0 :     NS_ASSERTION(!mParserBlockingRequest,
     732                 :         "Parser-blocking scripts and XSLT scripts in the same doc!");
     733               0 :     mXSLTRequests.AppendElement(request);
     734               0 :     return true;
     735                 :   }
     736               0 :   if (aElement->GetParserCreated() == NOT_FROM_PARSER) {
     737               0 :     NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
     738                 :         "A script-inserted script is inserted without an update batch?");
     739                 :     nsContentUtils::AddScriptRunner(new nsScriptRequestProcessor(this,
     740               0 :                                                                  request));
     741               0 :     return false;
     742                 :   }
     743               0 :   if (aElement->GetParserCreated() == FROM_PARSER_NETWORK &&
     744               0 :       !ReadyToExecuteScripts()) {
     745               0 :     NS_ASSERTION(!mParserBlockingRequest,
     746                 :         "There can be only one parser-blocking script at a time");
     747               0 :     mParserBlockingRequest = request;
     748               0 :     NS_ASSERTION(mXSLTRequests.IsEmpty(),
     749                 :         "Parser-blocking scripts and XSLT scripts in the same doc!");
     750               0 :     return true;
     751                 :   }
     752                 :   // We now have a document.written inline script or we have an inline script
     753                 :   // from the network but there is no style sheet that is blocking scripts.
     754                 :   // Don't check for style sheets blocking scripts in the document.write
     755                 :   // case to avoid style sheet network activity affecting when
     756                 :   // document.write returns. It's not really necessary to do this if
     757                 :   // there's no document.write currently on the call stack. However,
     758                 :   // this way matches IE more closely than checking if document.write
     759                 :   // is on the call stack.
     760               0 :   NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
     761                 :       "Not safe to run a parser-inserted script?");
     762               0 :   return ProcessRequest(request) == NS_ERROR_HTMLPARSER_BLOCK;
     763                 : }
     764                 : 
     765                 : nsresult
     766               0 : nsScriptLoader::ProcessRequest(nsScriptLoadRequest* aRequest)
     767                 : {
     768               0 :   NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
     769                 :                "Processing requests when running scripts is unsafe.");
     770                 : 
     771               0 :   NS_ENSURE_ARG(aRequest);
     772                 :   nsAFlatString* script;
     773               0 :   nsAutoString textData;
     774                 : 
     775                 :   NS_TIME_FUNCTION;
     776                 : 
     777               0 :   nsCOMPtr<nsIDocument> doc;
     778                 : 
     779               0 :   nsCOMPtr<nsINode> scriptElem = do_QueryInterface(aRequest->mElement);
     780                 : 
     781                 :   // If there's no script text, we try to get it from the element
     782               0 :   if (aRequest->mIsInline) {
     783                 :     // XXX This is inefficient - GetText makes multiple
     784                 :     // copies.
     785               0 :     aRequest->mElement->GetScriptText(textData);
     786                 : 
     787               0 :     script = &textData;
     788                 :   }
     789                 :   else {
     790               0 :     script = &aRequest->mScriptText;
     791                 : 
     792               0 :     doc = scriptElem->OwnerDoc();
     793                 :   }
     794                 : 
     795               0 :   nsCOMPtr<nsIScriptElement> oldParserInsertedScript;
     796               0 :   PRUint32 parserCreated = aRequest->mElement->GetParserCreated();
     797               0 :   if (parserCreated) {
     798               0 :     oldParserInsertedScript = mCurrentParserInsertedScript;
     799               0 :     mCurrentParserInsertedScript = aRequest->mElement;
     800                 :   }
     801                 : 
     802               0 :   FireScriptAvailable(NS_OK, aRequest);
     803                 : 
     804               0 :   bool runScript = true;
     805                 :   nsContentUtils::DispatchTrustedEvent(scriptElem->OwnerDoc(),
     806                 :                                        scriptElem,
     807               0 :                                        NS_LITERAL_STRING("beforescriptexecute"),
     808               0 :                                        true, true, &runScript);
     809                 : 
     810               0 :   nsresult rv = NS_OK;
     811               0 :   if (runScript) {
     812               0 :     if (doc) {
     813               0 :       doc->BeginEvaluatingExternalScript();
     814                 :     }
     815               0 :     aRequest->mElement->BeginEvaluating();
     816               0 :     rv = EvaluateScript(aRequest, *script);
     817               0 :     aRequest->mElement->EndEvaluating();
     818               0 :     if (doc) {
     819               0 :       doc->EndEvaluatingExternalScript();
     820                 :     }
     821                 : 
     822                 :     nsContentUtils::DispatchTrustedEvent(scriptElem->OwnerDoc(),
     823                 :                                          scriptElem,
     824               0 :                                          NS_LITERAL_STRING("afterscriptexecute"),
     825               0 :                                          true, false);
     826                 :   }
     827                 : 
     828               0 :   FireScriptEvaluated(rv, aRequest);
     829                 : 
     830               0 :   if (parserCreated) {
     831               0 :     mCurrentParserInsertedScript = oldParserInsertedScript;
     832                 :   }
     833                 : 
     834               0 :   return rv;
     835                 : }
     836                 : 
     837                 : void
     838               0 : nsScriptLoader::FireScriptAvailable(nsresult aResult,
     839                 :                                     nsScriptLoadRequest* aRequest)
     840                 : {
     841               0 :   for (PRInt32 i = 0; i < mObservers.Count(); i++) {
     842               0 :     nsCOMPtr<nsIScriptLoaderObserver> obs = mObservers[i];
     843               0 :     obs->ScriptAvailable(aResult, aRequest->mElement,
     844                 :                          aRequest->mIsInline, aRequest->mURI,
     845               0 :                          aRequest->mLineNo);
     846                 :   }
     847                 : 
     848               0 :   aRequest->FireScriptAvailable(aResult);
     849               0 : }
     850                 : 
     851                 : void
     852               0 : nsScriptLoader::FireScriptEvaluated(nsresult aResult,
     853                 :                                     nsScriptLoadRequest* aRequest)
     854                 : {
     855               0 :   for (PRInt32 i = 0; i < mObservers.Count(); i++) {
     856               0 :     nsCOMPtr<nsIScriptLoaderObserver> obs = mObservers[i];
     857               0 :     obs->ScriptEvaluated(aResult, aRequest->mElement,
     858               0 :                          aRequest->mIsInline);
     859                 :   }
     860                 : 
     861               0 :   aRequest->FireScriptEvaluated(aResult);
     862               0 : }
     863                 : 
     864                 : nsresult
     865               0 : nsScriptLoader::EvaluateScript(nsScriptLoadRequest* aRequest,
     866                 :                                const nsAFlatString& aScript)
     867                 : {
     868               0 :   nsresult rv = NS_OK;
     869                 : 
     870                 :   // We need a document to evaluate scripts.
     871               0 :   if (!mDocument) {
     872               0 :     return NS_ERROR_FAILURE;
     873                 :   }
     874                 : 
     875               0 :   nsCOMPtr<nsIContent> scriptContent(do_QueryInterface(aRequest->mElement));
     876               0 :   nsIDocument* ownerDoc = scriptContent->OwnerDoc();
     877               0 :   if (ownerDoc != mDocument) {
     878                 :     // Willful violation of HTML5 as of 2010-12-01
     879               0 :     return NS_ERROR_FAILURE;
     880                 :   }
     881                 : 
     882               0 :   nsPIDOMWindow *pwin = mDocument->GetInnerWindow();
     883               0 :   if (!pwin || !pwin->IsInnerWindow()) {
     884               0 :     return NS_ERROR_FAILURE;
     885                 :   }
     886               0 :   nsCOMPtr<nsIScriptGlobalObject> globalObject = do_QueryInterface(pwin);
     887               0 :   NS_ASSERTION(globalObject, "windows must be global objects");
     888                 : 
     889                 :   // Get the script-type to be used by this element.
     890               0 :   NS_ASSERTION(scriptContent, "no content - what is default script-type?");
     891               0 :   PRUint32 stid = scriptContent ? scriptContent->GetScriptTypeID() :
     892               0 :                                   nsIProgrammingLanguage::JAVASCRIPT;
     893                 :   // and make sure we are setup for this type of script.
     894               0 :   rv = globalObject->EnsureScriptEnvironment(stid);
     895               0 :   if (NS_FAILED(rv))
     896               0 :     return rv;
     897                 : 
     898                 :   // Make sure context is a strong reference since we access it after
     899                 :   // we've executed a script, which may cause all other references to
     900                 :   // the context to go away.
     901               0 :   nsCOMPtr<nsIScriptContext> context = globalObject->GetScriptContext(stid);
     902               0 :   if (!context) {
     903               0 :     return NS_ERROR_FAILURE;
     904                 :   }
     905                 : 
     906               0 :   bool oldProcessingScriptTag = context->GetProcessingScriptTag();
     907               0 :   context->SetProcessingScriptTag(true);
     908                 : 
     909                 :   // Update our current script.
     910               0 :   nsCOMPtr<nsIScriptElement> oldCurrent = mCurrentScript;
     911               0 :   mCurrentScript = aRequest->mElement;
     912                 : 
     913                 :   // It's very important to use aRequest->mURI, not the final URI of the channel
     914                 :   // aRequest ended up getting script data from, as the script filename.
     915               0 :   nsCAutoString url;
     916               0 :   nsContentUtils::GetWrapperSafeScriptFilename(mDocument, aRequest->mURI, url);
     917                 : 
     918                 :   bool isUndefined;
     919               0 :   rv = context->EvaluateString(aScript, globalObject->GetGlobalJSObject(),
     920                 :                                mDocument->NodePrincipal(),
     921                 :                                aRequest->mOriginPrincipal,
     922                 :                                url.get(), aRequest->mLineNo,
     923               0 :                                aRequest->mJSVersion, nsnull, &isUndefined);
     924                 : 
     925                 :   // Put the old script back in case it wants to do anything else.
     926               0 :   mCurrentScript = oldCurrent;
     927                 : 
     928               0 :   JSContext *cx = nsnull; // Initialize this to keep GCC happy.
     929               0 :   if (stid == nsIProgrammingLanguage::JAVASCRIPT) {
     930               0 :     cx = context->GetNativeContext();
     931               0 :     ::JS_BeginRequest(cx);
     932               0 :     NS_ASSERTION(!::JS_IsExceptionPending(cx),
     933                 :                  "JS_ReportPendingException wasn't called in EvaluateString");
     934                 :   }
     935                 : 
     936               0 :   context->SetProcessingScriptTag(oldProcessingScriptTag);
     937                 : 
     938               0 :   if (stid == nsIProgrammingLanguage::JAVASCRIPT) {
     939               0 :     NS_ASSERTION(!::JS_IsExceptionPending(cx),
     940                 :                  "JS_ReportPendingException wasn't called");
     941               0 :     ::JS_EndRequest(cx);
     942                 :   }
     943               0 :   return rv;
     944                 : }
     945                 : 
     946                 : void
     947               0 : nsScriptLoader::ProcessPendingRequestsAsync()
     948                 : {
     949               0 :   if (mParserBlockingRequest || !mPendingChildLoaders.IsEmpty()) {
     950                 :     nsCOMPtr<nsIRunnable> ev = NS_NewRunnableMethod(this,
     951               0 :       &nsScriptLoader::ProcessPendingRequests);
     952                 : 
     953               0 :     NS_DispatchToCurrentThread(ev);
     954                 :   }
     955               0 : }
     956                 : 
     957                 : void
     958            1038 : nsScriptLoader::ProcessPendingRequests()
     959                 : {
     960            2076 :   nsRefPtr<nsScriptLoadRequest> request;
     961            1038 :   if (mParserBlockingRequest &&
     962            1038 :       !mParserBlockingRequest->mLoading &&
     963               0 :       ReadyToExecuteScripts()) {
     964               0 :     request.swap(mParserBlockingRequest);
     965               0 :     UnblockParser(request);
     966               0 :     ProcessRequest(request);
     967               0 :     ContinueParserAsync(request);
     968                 :   }
     969                 : 
     970            2076 :   while (ReadyToExecuteScripts() && 
     971               0 :          !mXSLTRequests.IsEmpty() && 
     972               0 :          !mXSLTRequests[0]->mLoading) {
     973               0 :     request.swap(mXSLTRequests[0]);
     974               0 :     mXSLTRequests.RemoveElementAt(0);
     975               0 :     ProcessRequest(request);
     976                 :   }
     977                 : 
     978            1038 :   PRUint32 i = 0;
     979            2076 :   while (mEnabled && i < mAsyncRequests.Length()) {
     980               0 :     if (!mAsyncRequests[i]->mLoading) {
     981               0 :       request.swap(mAsyncRequests[i]);
     982               0 :       mAsyncRequests.RemoveElementAt(i);
     983               0 :       ProcessRequest(request);
     984               0 :       continue;
     985                 :     }
     986               0 :     ++i;
     987                 :   }
     988                 : 
     989            2076 :   while (mEnabled && !mNonAsyncExternalScriptInsertedRequests.IsEmpty() &&
     990               0 :          !mNonAsyncExternalScriptInsertedRequests[0]->mLoading) {
     991                 :     // Violate the HTML5 spec and execute these in the insertion order in
     992                 :     // order to make LABjs and the "order" plug-in for RequireJS work with
     993                 :     // their Gecko-sniffed code path. See
     994                 :     // http://lists.w3.org/Archives/Public/public-html/2010Oct/0088.html
     995               0 :     request.swap(mNonAsyncExternalScriptInsertedRequests[0]);
     996               0 :     mNonAsyncExternalScriptInsertedRequests.RemoveElementAt(0);
     997               0 :     ProcessRequest(request);
     998                 :   }
     999                 : 
    1000            1038 :   if (mDocumentParsingDone && mXSLTRequests.IsEmpty()) {
    1001            2076 :     while (!mDeferRequests.IsEmpty() && !mDeferRequests[0]->mLoading) {
    1002               0 :       request.swap(mDeferRequests[0]);
    1003               0 :       mDeferRequests.RemoveElementAt(0);
    1004               0 :       ProcessRequest(request);
    1005                 :     }
    1006                 :   }
    1007                 : 
    1008            2076 :   while (!mPendingChildLoaders.IsEmpty() && ReadyToExecuteScripts()) {
    1009               0 :     nsRefPtr<nsScriptLoader> child = mPendingChildLoaders[0];
    1010               0 :     mPendingChildLoaders.RemoveElementAt(0);
    1011               0 :     child->RemoveExecuteBlocker();
    1012                 :   }
    1013                 : 
    1014            6228 :   if (mDocumentParsingDone && mDocument &&
    1015            2076 :       !mParserBlockingRequest && mAsyncRequests.IsEmpty() &&
    1016            1038 :       mNonAsyncExternalScriptInsertedRequests.IsEmpty() &&
    1017            2076 :       mXSLTRequests.IsEmpty() && mDeferRequests.IsEmpty()) {
    1018                 :     // No more pending scripts; time to unblock onload.
    1019                 :     // OK to unblock onload synchronously here, since callers must be
    1020                 :     // prepared for the world changing anyway.
    1021            1038 :     mDocumentParsingDone = false;
    1022            1038 :     mDocument->UnblockOnload(true);
    1023                 :   }
    1024            1038 : }
    1025                 : 
    1026                 : bool
    1027            1038 : nsScriptLoader::ReadyToExecuteScripts()
    1028                 : {
    1029                 :   // Make sure the SelfReadyToExecuteScripts check is first, so that
    1030                 :   // we don't block twice on an ancestor.
    1031            1038 :   if (!SelfReadyToExecuteScripts()) {
    1032            1038 :     return false;
    1033                 :   }
    1034                 :   
    1035               0 :   for (nsIDocument* doc = mDocument; doc; doc = doc->GetParentDocument()) {
    1036               0 :     nsScriptLoader* ancestor = doc->ScriptLoader();
    1037               0 :     if (!ancestor->SelfReadyToExecuteScripts() &&
    1038               0 :         ancestor->AddPendingChildLoader(this)) {
    1039               0 :       AddExecuteBlocker();
    1040               0 :       return false;
    1041                 :     }
    1042                 :   }
    1043                 : 
    1044               0 :   return true;
    1045                 : }
    1046                 : 
    1047                 : 
    1048                 : // This function was copied from nsParser.cpp. It was simplified a bit.
    1049                 : static bool
    1050               0 : DetectByteOrderMark(const unsigned char* aBytes, PRInt32 aLen, nsCString& oCharset)
    1051                 : {
    1052               0 :   if (aLen < 2)
    1053               0 :     return false;
    1054                 : 
    1055               0 :   switch(aBytes[0]) {
    1056                 :   case 0xEF:
    1057               0 :     if (aLen >= 3 && 0xBB == aBytes[1] && 0xBF == aBytes[2]) {
    1058                 :       // EF BB BF
    1059                 :       // Win2K UTF-8 BOM
    1060               0 :       oCharset.Assign("UTF-8");
    1061                 :     }
    1062               0 :     break;
    1063                 :   case 0xFE:
    1064               0 :     if (0xFF == aBytes[1]) {
    1065                 :       // FE FF
    1066                 :       // UTF-16, big-endian
    1067               0 :       oCharset.Assign("UTF-16");
    1068                 :     }
    1069               0 :     break;
    1070                 :   case 0xFF:
    1071               0 :     if (0xFE == aBytes[1]) {
    1072                 :       // FF FE
    1073                 :       // UTF-16, little-endian
    1074               0 :       oCharset.Assign("UTF-16");
    1075                 :     }
    1076               0 :     break;
    1077                 :   }
    1078               0 :   return !oCharset.IsEmpty();
    1079                 : }
    1080                 : 
    1081                 : /* static */ nsresult
    1082               0 : nsScriptLoader::ConvertToUTF16(nsIChannel* aChannel, const PRUint8* aData,
    1083                 :                                PRUint32 aLength, const nsAString& aHintCharset,
    1084                 :                                nsIDocument* aDocument, nsString& aString)
    1085                 : {
    1086               0 :   if (!aLength) {
    1087               0 :     aString.Truncate();
    1088               0 :     return NS_OK;
    1089                 :   }
    1090                 : 
    1091               0 :   nsCAutoString characterSet;
    1092                 : 
    1093               0 :   nsresult rv = NS_OK;
    1094               0 :   if (aChannel) {
    1095               0 :     rv = aChannel->GetContentCharset(characterSet);
    1096                 :   }
    1097                 : 
    1098               0 :   if (!aHintCharset.IsEmpty() && (NS_FAILED(rv) || characterSet.IsEmpty())) {
    1099                 :     // charset name is always ASCII.
    1100               0 :     LossyCopyUTF16toASCII(aHintCharset, characterSet);
    1101                 :   }
    1102                 : 
    1103               0 :   if (NS_FAILED(rv) || characterSet.IsEmpty()) {
    1104               0 :     DetectByteOrderMark(aData, aLength, characterSet);
    1105                 :   }
    1106                 : 
    1107               0 :   if (characterSet.IsEmpty() && aDocument) {
    1108                 :     // charset from document default
    1109               0 :     characterSet = aDocument->GetDocumentCharacterSet();
    1110                 :   }
    1111                 : 
    1112               0 :   if (characterSet.IsEmpty()) {
    1113                 :     // fall back to ISO-8859-1, see bug 118404
    1114               0 :     characterSet.AssignLiteral("ISO-8859-1");
    1115                 :   }
    1116                 : 
    1117                 :   nsCOMPtr<nsICharsetConverterManager> charsetConv =
    1118               0 :     do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
    1119                 : 
    1120               0 :   nsCOMPtr<nsIUnicodeDecoder> unicodeDecoder;
    1121                 : 
    1122               0 :   if (NS_SUCCEEDED(rv) && charsetConv) {
    1123               0 :     rv = charsetConv->GetUnicodeDecoder(characterSet.get(),
    1124               0 :                                         getter_AddRefs(unicodeDecoder));
    1125               0 :     if (NS_FAILED(rv)) {
    1126                 :       // fall back to ISO-8859-1 if charset is not supported. (bug 230104)
    1127               0 :       rv = charsetConv->GetUnicodeDecoderRaw("ISO-8859-1",
    1128               0 :                                              getter_AddRefs(unicodeDecoder));
    1129                 :     }
    1130                 :   }
    1131                 : 
    1132                 :   // converts from the charset to unicode
    1133               0 :   if (NS_SUCCEEDED(rv)) {
    1134               0 :     PRInt32 unicodeLength = 0;
    1135                 : 
    1136               0 :     rv = unicodeDecoder->GetMaxLength(reinterpret_cast<const char*>(aData),
    1137               0 :                                       aLength, &unicodeLength);
    1138               0 :     if (NS_SUCCEEDED(rv)) {
    1139               0 :       if (!EnsureStringLength(aString, unicodeLength))
    1140               0 :         return NS_ERROR_OUT_OF_MEMORY;
    1141                 : 
    1142               0 :       PRUnichar *ustr = aString.BeginWriting();
    1143                 : 
    1144               0 :       PRInt32 consumedLength = 0;
    1145               0 :       PRInt32 originalLength = aLength;
    1146               0 :       PRInt32 convertedLength = 0;
    1147               0 :       PRInt32 bufferLength = unicodeLength;
    1148               0 :       do {
    1149               0 :         rv = unicodeDecoder->Convert(reinterpret_cast<const char*>(aData),
    1150                 :                                      (PRInt32 *) &aLength, ustr,
    1151               0 :                                      &unicodeLength);
    1152               0 :         if (NS_FAILED(rv)) {
    1153                 :           // if we failed, we consume one byte, replace it with U+FFFD
    1154                 :           // and try the conversion again.
    1155               0 :           ustr[unicodeLength++] = (PRUnichar)0xFFFD;
    1156               0 :           ustr += unicodeLength;
    1157                 : 
    1158               0 :           unicodeDecoder->Reset();
    1159                 :         }
    1160               0 :         aData += ++aLength;
    1161               0 :         consumedLength += aLength;
    1162               0 :         aLength = originalLength - consumedLength;
    1163               0 :         convertedLength += unicodeLength;
    1164               0 :         unicodeLength = bufferLength - convertedLength;
    1165               0 :       } while (NS_FAILED(rv) && (originalLength > consumedLength) && (bufferLength > convertedLength));
    1166               0 :       aString.SetLength(convertedLength);
    1167                 :     }
    1168                 :   }
    1169               0 :   return rv;
    1170                 : }
    1171                 : 
    1172                 : NS_IMETHODIMP
    1173               0 : nsScriptLoader::OnStreamComplete(nsIStreamLoader* aLoader,
    1174                 :                                  nsISupports* aContext,
    1175                 :                                  nsresult aStatus,
    1176                 :                                  PRUint32 aStringLen,
    1177                 :                                  const PRUint8* aString)
    1178                 : {
    1179               0 :   nsScriptLoadRequest* request = static_cast<nsScriptLoadRequest*>(aContext);
    1180               0 :   NS_ASSERTION(request, "null request in stream complete handler");
    1181               0 :   NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
    1182                 : 
    1183                 :   nsresult rv = PrepareLoadedRequest(request, aLoader, aStatus, aStringLen,
    1184               0 :                                      aString);
    1185               0 :   if (NS_FAILED(rv)) {
    1186               0 :     if (mDeferRequests.RemoveElement(request) ||
    1187               0 :         mAsyncRequests.RemoveElement(request) ||
    1188               0 :         mNonAsyncExternalScriptInsertedRequests.RemoveElement(request) ||
    1189               0 :         mXSLTRequests.RemoveElement(request)) {
    1190               0 :       FireScriptAvailable(rv, request);
    1191               0 :     } else if (mParserBlockingRequest == request) {
    1192               0 :       mParserBlockingRequest = nsnull;
    1193               0 :       UnblockParser(request);
    1194               0 :       FireScriptAvailable(rv, request);
    1195               0 :       ContinueParserAsync(request);
    1196                 :     } else {
    1197               0 :       mPreloads.RemoveElement(request, PreloadRequestComparator());
    1198                 :     }
    1199                 :   }
    1200                 : 
    1201                 :   // Process our request and/or any pending ones
    1202               0 :   ProcessPendingRequests();
    1203                 : 
    1204               0 :   return NS_OK;
    1205                 : }
    1206                 : 
    1207                 : void
    1208               0 : nsScriptLoader::UnblockParser(nsScriptLoadRequest* aParserBlockingRequest)
    1209                 : {
    1210               0 :   aParserBlockingRequest->mElement->UnblockParser();
    1211               0 : }
    1212                 : 
    1213                 : void
    1214               0 : nsScriptLoader::ContinueParserAsync(nsScriptLoadRequest* aParserBlockingRequest)
    1215                 : {
    1216               0 :   aParserBlockingRequest->mElement->ContinueParserAsync();
    1217               0 : }
    1218                 : 
    1219                 : nsresult
    1220               0 : nsScriptLoader::PrepareLoadedRequest(nsScriptLoadRequest* aRequest,
    1221                 :                                      nsIStreamLoader* aLoader,
    1222                 :                                      nsresult aStatus,
    1223                 :                                      PRUint32 aStringLen,
    1224                 :                                      const PRUint8* aString)
    1225                 : {
    1226               0 :   if (NS_FAILED(aStatus)) {
    1227               0 :     return aStatus;
    1228                 :   }
    1229                 : 
    1230                 :   // If we don't have a document, then we need to abort further
    1231                 :   // evaluation.
    1232               0 :   if (!mDocument) {
    1233               0 :     return NS_ERROR_NOT_AVAILABLE;
    1234                 :   }
    1235                 : 
    1236                 :   // If the load returned an error page, then we need to abort
    1237               0 :   nsCOMPtr<nsIRequest> req;
    1238               0 :   nsresult rv = aLoader->GetRequest(getter_AddRefs(req));
    1239               0 :   NS_ASSERTION(req, "StreamLoader's request went away prematurely");
    1240               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1241                 : 
    1242               0 :   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(req);
    1243               0 :   if (httpChannel) {
    1244                 :     bool requestSucceeded;
    1245               0 :     rv = httpChannel->GetRequestSucceeded(&requestSucceeded);
    1246               0 :     if (NS_SUCCEEDED(rv) && !requestSucceeded) {
    1247               0 :       return NS_ERROR_NOT_AVAILABLE;
    1248                 :     }
    1249                 :   }
    1250                 : 
    1251               0 :   nsCOMPtr<nsIChannel> channel = do_QueryInterface(req);
    1252                 :   // If this load was subject to a CORS check; don't flag it with a
    1253                 :   // separate origin principal, so that it will treat our document's
    1254                 :   // principal as the origin principal
    1255               0 :   if (aRequest->mCORSMode == CORS_NONE) {
    1256               0 :     rv = nsContentUtils::GetSecurityManager()->
    1257               0 :       GetChannelPrincipal(channel, getter_AddRefs(aRequest->mOriginPrincipal));
    1258               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1259                 :   }
    1260                 : 
    1261               0 :   if (aStringLen) {
    1262                 :     // Check the charset attribute to determine script charset.
    1263               0 :     nsAutoString hintCharset;
    1264               0 :     if (!aRequest->IsPreload()) {
    1265               0 :       aRequest->mElement->GetScriptCharset(hintCharset);
    1266                 :     } else {
    1267                 :       nsTArray<PreloadInfo>::index_type i =
    1268               0 :         mPreloads.IndexOf(aRequest, 0, PreloadRequestComparator());
    1269               0 :       NS_ASSERTION(i != mPreloads.NoIndex, "Incorrect preload bookkeeping");
    1270               0 :       hintCharset = mPreloads[i].mCharset;
    1271                 :     }
    1272                 :     rv = ConvertToUTF16(channel, aString, aStringLen, hintCharset, mDocument,
    1273               0 :                         aRequest->mScriptText);
    1274                 : 
    1275               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1276                 : 
    1277               0 :     if (!ShouldExecuteScript(mDocument, channel)) {
    1278               0 :       return NS_ERROR_NOT_AVAILABLE;
    1279                 :     }
    1280                 :   }
    1281                 : 
    1282                 :   // This assertion could fire errorously if we ran out of memory when
    1283                 :   // inserting the request in the array. However it's an unlikely case
    1284                 :   // so if you see this assertion it is likely something else that is
    1285                 :   // wrong, especially if you see it more than once.
    1286               0 :   NS_ASSERTION(mDeferRequests.IndexOf(aRequest) >= 0 ||
    1287                 :                mAsyncRequests.IndexOf(aRequest) >= 0 ||
    1288                 :                mNonAsyncExternalScriptInsertedRequests.IndexOf(aRequest) >= 0 ||
    1289                 :                mXSLTRequests.IndexOf(aRequest) >= 0 ||
    1290                 :                mPreloads.Contains(aRequest, PreloadRequestComparator()) ||
    1291                 :                mParserBlockingRequest,
    1292                 :                "aRequest should be pending!");
    1293                 : 
    1294                 :   // Mark this as loaded
    1295               0 :   aRequest->mLoading = false;
    1296                 : 
    1297               0 :   return NS_OK;
    1298                 : }
    1299                 : 
    1300                 : /* static */
    1301                 : bool
    1302               0 : nsScriptLoader::ShouldExecuteScript(nsIDocument* aDocument,
    1303                 :                                     nsIChannel* aChannel)
    1304                 : {
    1305               0 :   if (!aChannel) {
    1306               0 :     return false;
    1307                 :   }
    1308                 : 
    1309                 :   bool hasCert;
    1310               0 :   nsIPrincipal* docPrincipal = aDocument->NodePrincipal();
    1311               0 :   docPrincipal->GetHasCertificate(&hasCert);
    1312               0 :   if (!hasCert) {
    1313               0 :     return true;
    1314                 :   }
    1315                 : 
    1316               0 :   nsCOMPtr<nsIPrincipal> channelPrincipal;
    1317               0 :   nsresult rv = nsContentUtils::GetSecurityManager()->
    1318               0 :     GetChannelPrincipal(aChannel, getter_AddRefs(channelPrincipal));
    1319               0 :   NS_ENSURE_SUCCESS(rv, false);
    1320                 : 
    1321               0 :   NS_ASSERTION(channelPrincipal, "Gotta have a principal here!");
    1322                 : 
    1323                 :   // If the channel principal isn't at least as powerful as the
    1324                 :   // document principal, then we don't execute the script.
    1325                 :   bool subsumes;
    1326               0 :   rv = channelPrincipal->Subsumes(docPrincipal, &subsumes);
    1327               0 :   return NS_SUCCEEDED(rv) && subsumes;
    1328                 : }
    1329                 : 
    1330                 : void
    1331            1038 : nsScriptLoader::ParsingComplete(bool aTerminated)
    1332                 : {
    1333            1038 :   if (mDeferEnabled) {
    1334                 :     // Have to check because we apparently get ParsingComplete
    1335                 :     // without BeginDeferringScripts in some cases
    1336            1038 :     mDocumentParsingDone = true;
    1337                 :   }
    1338            1038 :   mDeferEnabled = false;
    1339            1038 :   if (aTerminated) {
    1340              62 :     mDeferRequests.Clear();
    1341              62 :     mAsyncRequests.Clear();
    1342              62 :     mNonAsyncExternalScriptInsertedRequests.Clear();
    1343              62 :     mXSLTRequests.Clear();
    1344              62 :     mParserBlockingRequest = nsnull;
    1345                 :   }
    1346                 : 
    1347                 :   // Have to call this even if aTerminated so we'll correctly unblock
    1348                 :   // onload and all.
    1349            1038 :   ProcessPendingRequests();
    1350            1038 : }
    1351                 : 
    1352                 : void
    1353               0 : nsScriptLoader::PreloadURI(nsIURI *aURI, const nsAString &aCharset,
    1354                 :                            const nsAString &aType,
    1355                 :                            const nsAString &aCrossOrigin)
    1356                 : {
    1357                 :   // Check to see if scripts has been turned off.
    1358               0 :   if (!mEnabled || !mDocument->IsScriptEnabled()) {
    1359               0 :     return;
    1360                 :   }
    1361                 : 
    1362                 :   nsRefPtr<nsScriptLoadRequest> request =
    1363                 :     new nsScriptLoadRequest(nsnull, 0,
    1364               0 :                             nsGenericElement::StringToCORSMode(aCrossOrigin));
    1365               0 :   request->mURI = aURI;
    1366               0 :   request->mIsInline = false;
    1367               0 :   request->mLoading = true;
    1368               0 :   nsresult rv = StartLoad(request, aType);
    1369               0 :   if (NS_FAILED(rv)) {
    1370                 :     return;
    1371                 :   }
    1372                 : 
    1373               0 :   PreloadInfo *pi = mPreloads.AppendElement();
    1374               0 :   pi->mRequest = request;
    1375               0 :   pi->mCharset = aCharset;
    1376                 : }

Generated by: LCOV version 1.7