/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ // vim: ft=cpp tw=78 sw=4 et ts=8 /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* * Implementation of the "@mozilla.org/layout/content-policy;1" contract. */ #include "prlog.h" #include "nsISupports.h" #include "nsXPCOM.h" #include "nsContentPolicyUtils.h" #include "nsContentPolicy.h" #include "nsIURI.h" #include "nsIDOMNode.h" #include "nsIDOMWindow.h" #include "nsIContent.h" #include "nsCOMArray.h" NS_IMPL_ISUPPORTS(nsContentPolicy, nsIContentPolicy) #ifdef PR_LOGGING static PRLogModuleInfo* gConPolLog; #endif nsresult NS_NewContentPolicy(nsIContentPolicy **aResult) { *aResult = new nsContentPolicy; if (!*aResult) return NS_ERROR_OUT_OF_MEMORY; NS_ADDREF(*aResult); return NS_OK; } nsContentPolicy::nsContentPolicy() : mPolicies(NS_CONTENTPOLICY_CATEGORY) { #ifdef PR_LOGGING if (! gConPolLog) { gConPolLog = PR_NewLogModule("nsContentPolicy"); } #endif } nsContentPolicy::~nsContentPolicy() { } #ifdef DEBUG #define WARN_IF_URI_UNINITIALIZED(uri,name) \ PR_BEGIN_MACRO \ if ((uri)) { \ nsAutoCString spec; \ (uri)->GetAsciiSpec(spec); \ if (spec.IsEmpty()) { \ NS_WARNING(name " is uninitialized, fix caller"); \ } \ } \ PR_END_MACRO #else // ! defined(DEBUG) #define WARN_IF_URI_UNINITIALIZED(uri,name) #endif // defined(DEBUG) inline nsresult nsContentPolicy::CheckPolicy(CPMethod policyMethod, uint32_t contentType, nsIURI *contentLocation, nsIURI *requestingLocation, nsISupports *requestingContext, const nsACString &mimeType, nsISupports *extra, nsIPrincipal *requestPrincipal, int16_t *decision) { //sanity-check passed-through parameters NS_PRECONDITION(decision, "Null out pointer"); WARN_IF_URI_UNINITIALIZED(contentLocation, "Request URI"); WARN_IF_URI_UNINITIALIZED(requestingLocation, "Requesting URI"); #ifdef DEBUG { nsCOMPtr node(do_QueryInterface(requestingContext)); nsCOMPtr window(do_QueryInterface(requestingContext)); NS_ASSERTION(!requestingContext || node || window, "Context should be a DOM node or a DOM window!"); } #endif /* * There might not be a requestinglocation. This can happen for * iframes with an image as src. Get the uri from the dom node. * See bug 254510 */ if (!requestingLocation) { nsCOMPtr doc; nsCOMPtr node = do_QueryInterface(requestingContext); if (node) { doc = node->OwnerDoc(); } if (!doc) { doc = do_QueryInterface(requestingContext); } if (doc) { requestingLocation = doc->GetDocumentURI(); } } /* * Enumerate mPolicies and ask each of them, taking the logical AND of * their permissions. */ nsresult rv; nsCOMArray entries; mPolicies.GetEntries(entries); int32_t count = entries.Count(); for (int32_t i = 0; i < count; i++) { /* check the appropriate policy */ rv = (entries[i]->*policyMethod)(contentType, contentLocation, requestingLocation, requestingContext, mimeType, extra, requestPrincipal, decision); if (NS_SUCCEEDED(rv) && NS_CP_REJECTED(*decision)) { /* policy says no, no point continuing to check */ return NS_OK; } } // everyone returned failure, or no policies: sanitize result *decision = nsIContentPolicy::ACCEPT; return NS_OK; } #ifdef PR_LOGGING //uses the parameters from ShouldXYZ to produce and log a message //logType must be a literal string constant #define LOG_CHECK(logType) \ PR_BEGIN_MACRO \ /* skip all this nonsense if the call failed */ \ if (NS_SUCCEEDED(rv)) { \ const char *resultName; \ if (decision) { \ resultName = NS_CP_ResponseName(*decision); \ } else { \ resultName = "(null ptr)"; \ } \ nsAutoCString spec("None"); \ if (contentLocation) { \ contentLocation->GetSpec(spec); \ } \ nsAutoCString refSpec("None"); \ if (requestingLocation) { \ requestingLocation->GetSpec(refSpec); \ } \ PR_LOG(gConPolLog, PR_LOG_DEBUG, \ ("Content Policy: " logType ": <%s> result=%s", \ spec.get(), refSpec.get(), resultName) \ ); \ } \ PR_END_MACRO #else //!defined(PR_LOGGING) #define LOG_CHECK(logType) #endif //!defined(PR_LOGGING) NS_IMETHODIMP nsContentPolicy::ShouldLoad(uint32_t contentType, nsIURI *contentLocation, nsIURI *requestingLocation, nsISupports *requestingContext, const nsACString &mimeType, nsISupports *extra, nsIPrincipal *requestPrincipal, int16_t *decision) { // ShouldProcess does not need a content location, but we do NS_PRECONDITION(contentLocation, "Must provide request location"); nsresult rv = CheckPolicy(&nsIContentPolicy::ShouldLoad, contentType, contentLocation, requestingLocation, requestingContext, mimeType, extra, requestPrincipal, decision); LOG_CHECK("ShouldLoad"); return rv; } NS_IMETHODIMP nsContentPolicy::ShouldProcess(uint32_t contentType, nsIURI *contentLocation, nsIURI *requestingLocation, nsISupports *requestingContext, const nsACString &mimeType, nsISupports *extra, nsIPrincipal *requestPrincipal, int16_t *decision) { nsresult rv = CheckPolicy(&nsIContentPolicy::ShouldProcess, contentType, contentLocation, requestingLocation, requestingContext, mimeType, extra, requestPrincipal, decision); LOG_CHECK("ShouldProcess"); return rv; }