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