/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * 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 the Initial Developer are Copyright (C) 2001 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Vidur Apparao (original author) * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsScriptLoader.h" #include "nsIDOMCharacterData.h" #include "nsParserUtils.h" #include "nsICharsetConverterManager.h" #include "nsIUnicodeDecoder.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(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CID); ////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////// static already_AddRefed IntersectPrincipalCerts(nsIPrincipal *aOld, nsIPrincipal *aNew) { NS_PRECONDITION(aOld, "Null old principal!"); NS_PRECONDITION(aNew, "Null new principal!"); nsIPrincipal *principal = aOld; PRBool hasCert; aOld->GetHasCertificate(&hasCert); if (hasCert) { PRBool equal; aOld->Equals(aNew, &equal); if (!equal) { nsCOMPtr uri, domain; aOld->GetURI(getter_AddRefs(uri)); aOld->GetDomain(getter_AddRefs(domain)); nsContentUtils::GetSecurityManager()->GetCodebasePrincipal(uri, &principal); if (principal && domain) { principal->SetDomain(domain); } return principal; } } NS_ADDREF(principal); return principal; } ////////////////////////////////////////////////////////////// // 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? nsString mScriptText; // Holds script for loaded scripts 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, EmptyString()); } } 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; } nsINodeInfo *nodeInfo = content->GetNodeInfo(); NS_ASSERTION(nodeInfo, "element without node info"); if (nodeInfo) { nsIAtom *localName = nodeInfo->NameAtom(); // 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 == nsHTMLAtoms::iframe) || (localName == nsHTMLAtoms::noframes) || (localName == 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 //