/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is Mozilla. * * The Initial Developer of the Original Code is Netscape * Communications. Portions created by Netscape Communications are * Copyright (C) 2001 by Netscape Communications. All * Rights Reserved. * * Contributor(s): * Vidur Apparao (original author) */ #include "nsScriptLoader.h" #include "nsIDOMCharacterData.h" #include "nsParserUtils.h" #include "nsICharsetConverterManager.h" #include "nsIUnicodeDecoder.h" #include "nsICharsetAlias.h" #include "nsIContent.h" #include "nsHTMLAtoms.h" #include "nsNetUtil.h" #include "nsIScriptGlobalObject.h" #include "nsIScriptContext.h" #include "nsINodeInfo.h" #include "nsIScriptSecurityManager.h" #include "nsIPrincipal.h" #include "nsContentPolicyUtils.h" #include "nsIDOMWindow.h" #include "nsIHttpChannel.h" #include "nsIScriptElement.h" #include "nsIDocShell.h" #include "jsapi.h" #include "nsContentUtils.h" #include "nsUnicharUtils.h" #include "nsAutoPtr.h" static NS_DEFINE_CID(kCharsetAliasCID, NS_CHARSETALIAS_CID); static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CID); ////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////// // Per-request data structure ////////////////////////////////////////////////////////////// class nsScriptLoadRequest : public nsISupports { public: nsScriptLoadRequest(nsIDOMHTMLScriptElement* aElement, nsIScriptLoaderObserver* aObserver, const char* aVersionString); virtual ~nsScriptLoadRequest(); NS_DECL_ISUPPORTS void FireScriptAvailable(nsresult aResult, const nsAFlatString& aScript); void FireScriptEvaluated(nsresult aResult); nsCOMPtr mElement; nsCOMPtr mObserver; PRPackedBool mLoading; // Are we still waiting for a load to complete? PRPackedBool mWasPending; // Processed immediately or pending PRPackedBool mIsInline; // Is the script inline or loaded? // nsSharableString mScriptText; // Holds script for loaded scripts nsString mScriptText; const char* mJSVersion; // We don't own this string nsCOMPtr mURI; PRInt32 mLineNo; }; nsScriptLoadRequest::nsScriptLoadRequest(nsIDOMHTMLScriptElement* aElement, nsIScriptLoaderObserver* aObserver, const char* aVersionString) : mElement(aElement), mObserver(aObserver), mLoading(PR_TRUE), mWasPending(PR_FALSE), mIsInline(PR_TRUE), mJSVersion(aVersionString), mLineNo(1) { } nsScriptLoadRequest::~nsScriptLoadRequest() { } // The nsScriptLoadRequest is passed as the context to necko, and thus // it needs to be threadsafe. Necko won't do anything with this // context, but it will AddRef and Release it on other threads. NS_IMPL_THREADSAFE_ISUPPORTS0(nsScriptLoadRequest) void nsScriptLoadRequest::FireScriptAvailable(nsresult aResult, const nsAFlatString& aScript) { if (mObserver) { mObserver->ScriptAvailable(aResult, mElement, mIsInline, mWasPending, mURI, mLineNo, aScript); } } void nsScriptLoadRequest::FireScriptEvaluated(nsresult aResult) { if (mObserver) { mObserver->ScriptEvaluated(aResult, mElement, mIsInline, mWasPending); } } ////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////// nsScriptLoader::nsScriptLoader() : mDocument(nsnull), mEnabled(PR_TRUE) { } nsScriptLoader::~nsScriptLoader() { mObservers.Clear(); PRInt32 count = mPendingRequests.Count(); for (PRInt32 i = 0; i < count; i++) { nsScriptLoadRequest* req = mPendingRequests[i]; if (req) { req->FireScriptAvailable(NS_ERROR_ABORT, NS_LITERAL_STRING("")); } } mPendingRequests.Clear(); } NS_INTERFACE_MAP_BEGIN(nsScriptLoader) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIScriptLoader) NS_INTERFACE_MAP_ENTRY(nsIScriptLoader) NS_INTERFACE_MAP_ENTRY(nsIStreamLoaderObserver) NS_INTERFACE_MAP_END NS_IMPL_ADDREF(nsScriptLoader) NS_IMPL_RELEASE(nsScriptLoader) /* void init (in nsIDocument aDocument); */ NS_IMETHODIMP nsScriptLoader::Init(nsIDocument *aDocument) { mDocument = aDocument; return NS_OK; } /* void dropDocumentReference (); */ NS_IMETHODIMP nsScriptLoader::DropDocumentReference() { mDocument = nsnull; return NS_OK; } /* void addObserver (in nsIScriptLoaderObserver aObserver); */ NS_IMETHODIMP nsScriptLoader::AddObserver(nsIScriptLoaderObserver *aObserver) { NS_ENSURE_ARG(aObserver); mObservers.AppendObject(aObserver); return NS_OK; } /* void removeObserver (in nsIScriptLoaderObserver aObserver); */ NS_IMETHODIMP nsScriptLoader::RemoveObserver(nsIScriptLoaderObserver *aObserver) { NS_ENSURE_ARG(aObserver); mObservers.RemoveObject(aObserver); return NS_OK; } PRBool nsScriptLoader::InNonScriptingContainer(nsIDOMHTMLScriptElement* aScriptElement) { nsCOMPtr node(do_QueryInterface(aScriptElement)); nsCOMPtr parent; node->GetParentNode(getter_AddRefs(parent)); while (parent) { nsCOMPtr content(do_QueryInterface(parent)); if (!content) { break; } nsCOMPtr nodeInfo; content->GetNodeInfo(getter_AddRefs(nodeInfo)); NS_ASSERTION(nodeInfo, "element without node info"); if (nodeInfo) { nsCOMPtr localName = nodeInfo->GetNameAtom(); // XXX noframes and noembed are currently unconditionally not // displayed and processed. This might change if we support either // prefs or per-document container settings for not allowing // frames or plugins. if (content->IsContentOfType(nsIContent::eHTML) && ((localName.get() == nsHTMLAtoms::iframe) || (localName.get() == nsHTMLAtoms::noframes) || (localName.get() == nsHTMLAtoms::noembed))) { return PR_TRUE; } } node = parent; node->GetParentNode(getter_AddRefs(parent)); } return PR_FALSE; } // Helper method for checking if the script element is an event-handler // This means that it has both a for-attribute and a event-attribute. // Also, if the for-attribute has a value that matches "\s*window\s*", // and the event-attribute matches "\s*onload([ \(].*)?" then it isn't an // eventhandler. (both matches are case insensitive). // This is how IE seems to filter out a window's onload handler from a //