diff -r 000000000000 -r 6474c204b198 content/base/src/nsContentPolicy.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/content/base/src/nsContentPolicy.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,214 @@ +/* -*- 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; +}