1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/base/public/nsContentPolicyUtils.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,311 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* 1.10 + * Utility routines for checking content load/process policy settings, 1.11 + * and routines helpful for content policy implementors. 1.12 + * 1.13 + * XXXbz it would be nice if some of this stuff could be out-of-lined in 1.14 + * nsContentUtils. That would work for almost all the callers... 1.15 + */ 1.16 + 1.17 +#ifndef __nsContentPolicyUtils_h__ 1.18 +#define __nsContentPolicyUtils_h__ 1.19 + 1.20 +#include "nsIContentPolicy.h" 1.21 +#include "nsIContent.h" 1.22 +#include "nsIScriptSecurityManager.h" 1.23 +#include "nsIURI.h" 1.24 +#include "nsServiceManagerUtils.h" 1.25 + 1.26 +//XXXtw sadly, this makes consumers of nsContentPolicyUtils depend on widget 1.27 +#include "nsIDocument.h" 1.28 +#include "nsPIDOMWindow.h" 1.29 + 1.30 +class nsACString; 1.31 +class nsIPrincipal; 1.32 + 1.33 +#define NS_CONTENTPOLICY_CONTRACTID "@mozilla.org/layout/content-policy;1" 1.34 +#define NS_CONTENTPOLICY_CATEGORY "content-policy" 1.35 +#define NS_CONTENTPOLICY_CID \ 1.36 + {0x0e3afd3d, 0xeb60, 0x4c2b, \ 1.37 + { 0x96, 0x3b, 0x56, 0xd7, 0xc4, 0x39, 0xf1, 0x24 }} 1.38 + 1.39 +/** 1.40 + * Evaluates to true if val is ACCEPT. 1.41 + * 1.42 + * @param val the status returned from shouldProcess/shouldLoad 1.43 + */ 1.44 +#define NS_CP_ACCEPTED(val) ((val) == nsIContentPolicy::ACCEPT) 1.45 + 1.46 +/** 1.47 + * Evaluates to true if val is a REJECT_* status 1.48 + * 1.49 + * @param val the status returned from shouldProcess/shouldLoad 1.50 + */ 1.51 +#define NS_CP_REJECTED(val) ((val) != nsIContentPolicy::ACCEPT) 1.52 + 1.53 +// Offer convenient translations of constants -> const char* 1.54 + 1.55 +// convenience macro to reduce some repetative typing... 1.56 +// name is the name of a constant from this interface 1.57 +#define CASE_RETURN(name) \ 1.58 + case nsIContentPolicy:: name : \ 1.59 + return #name 1.60 + 1.61 +#ifdef PR_LOGGING 1.62 +/** 1.63 + * Returns a string corresponding to the name of the response constant, or 1.64 + * "<Unknown Response>" if an unknown response value is given. 1.65 + * 1.66 + * The return value is static and must not be freed. 1.67 + * 1.68 + * @param response the response code 1.69 + * @return the name of the given response code 1.70 + */ 1.71 +inline const char * 1.72 +NS_CP_ResponseName(int16_t response) 1.73 +{ 1.74 + switch (response) { 1.75 + CASE_RETURN( REJECT_REQUEST ); 1.76 + CASE_RETURN( REJECT_TYPE ); 1.77 + CASE_RETURN( REJECT_SERVER ); 1.78 + CASE_RETURN( REJECT_OTHER ); 1.79 + CASE_RETURN( ACCEPT ); 1.80 + default: 1.81 + return "<Unknown Response>"; 1.82 + } 1.83 +} 1.84 + 1.85 +/** 1.86 + * Returns a string corresponding to the name of the content type constant, or 1.87 + * "<Unknown Type>" if an unknown content type value is given. 1.88 + * 1.89 + * The return value is static and must not be freed. 1.90 + * 1.91 + * @param contentType the content type code 1.92 + * @return the name of the given content type code 1.93 + */ 1.94 +inline const char * 1.95 +NS_CP_ContentTypeName(uint32_t contentType) 1.96 +{ 1.97 + switch (contentType) { 1.98 + CASE_RETURN( TYPE_OTHER ); 1.99 + CASE_RETURN( TYPE_SCRIPT ); 1.100 + CASE_RETURN( TYPE_IMAGE ); 1.101 + CASE_RETURN( TYPE_STYLESHEET ); 1.102 + CASE_RETURN( TYPE_OBJECT ); 1.103 + CASE_RETURN( TYPE_DOCUMENT ); 1.104 + CASE_RETURN( TYPE_SUBDOCUMENT ); 1.105 + CASE_RETURN( TYPE_REFRESH ); 1.106 + CASE_RETURN( TYPE_XBL ); 1.107 + CASE_RETURN( TYPE_PING ); 1.108 + CASE_RETURN( TYPE_XMLHTTPREQUEST ); 1.109 + CASE_RETURN( TYPE_OBJECT_SUBREQUEST ); 1.110 + CASE_RETURN( TYPE_DTD ); 1.111 + CASE_RETURN( TYPE_FONT ); 1.112 + CASE_RETURN( TYPE_MEDIA ); 1.113 + CASE_RETURN( TYPE_WEBSOCKET ); 1.114 + CASE_RETURN( TYPE_CSP_REPORT ); 1.115 + CASE_RETURN( TYPE_XSLT ); 1.116 + CASE_RETURN( TYPE_BEACON ); 1.117 + default: 1.118 + return "<Unknown Type>"; 1.119 + } 1.120 +} 1.121 + 1.122 +#endif // defined(PR_LOGGING) 1.123 + 1.124 +#undef CASE_RETURN 1.125 + 1.126 +/* Passes on parameters from its "caller"'s context. */ 1.127 +#define CHECK_CONTENT_POLICY(action) \ 1.128 + PR_BEGIN_MACRO \ 1.129 + nsCOMPtr<nsIContentPolicy> policy = \ 1.130 + do_GetService(NS_CONTENTPOLICY_CONTRACTID); \ 1.131 + if (!policy) \ 1.132 + return NS_ERROR_FAILURE; \ 1.133 + \ 1.134 + return policy-> action (contentType, contentLocation, requestOrigin, \ 1.135 + context, mimeType, extra, originPrincipal, \ 1.136 + decision); \ 1.137 + PR_END_MACRO 1.138 + 1.139 +/* Passes on parameters from its "caller"'s context. */ 1.140 +#define CHECK_CONTENT_POLICY_WITH_SERVICE(action, _policy) \ 1.141 + PR_BEGIN_MACRO \ 1.142 + return _policy-> action (contentType, contentLocation, requestOrigin, \ 1.143 + context, mimeType, extra, originPrincipal, \ 1.144 + decision); \ 1.145 + PR_END_MACRO 1.146 + 1.147 +/** 1.148 + * Check whether we can short-circuit this check and bail out. If not, get the 1.149 + * origin URI to use. 1.150 + * 1.151 + * Note: requestOrigin is scoped outside the PR_BEGIN_MACRO/PR_END_MACRO on 1.152 + * purpose */ 1.153 +#define CHECK_PRINCIPAL_AND_DATA(action) \ 1.154 + nsCOMPtr<nsIURI> requestOrigin; \ 1.155 + PR_BEGIN_MACRO \ 1.156 + if (originPrincipal) { \ 1.157 + nsCOMPtr<nsIScriptSecurityManager> secMan = aSecMan; \ 1.158 + if (!secMan) { \ 1.159 + secMan = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID); \ 1.160 + } \ 1.161 + if (secMan) { \ 1.162 + bool isSystem; \ 1.163 + nsresult rv = secMan->IsSystemPrincipal(originPrincipal, \ 1.164 + &isSystem); \ 1.165 + NS_ENSURE_SUCCESS(rv, rv); \ 1.166 + if (isSystem) { \ 1.167 + *decision = nsIContentPolicy::ACCEPT; \ 1.168 + nsCOMPtr<nsINode> n = do_QueryInterface(context); \ 1.169 + if (!n) { \ 1.170 + nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(context); \ 1.171 + n = win ? win->GetExtantDoc() : nullptr; \ 1.172 + } \ 1.173 + if (n) { \ 1.174 + nsIDocument* d = n->OwnerDoc(); \ 1.175 + if (d->IsLoadedAsData() || d->IsBeingUsedAsImage() || \ 1.176 + d->IsResourceDoc()) { \ 1.177 + nsCOMPtr<nsIContentPolicy> dataPolicy = \ 1.178 + do_GetService( \ 1.179 + "@mozilla.org/data-document-content-policy;1"); \ 1.180 + if (dataPolicy) { \ 1.181 + dataPolicy-> action (contentType, contentLocation, \ 1.182 + requestOrigin, context, \ 1.183 + mimeType, extra, \ 1.184 + originPrincipal, decision); \ 1.185 + } \ 1.186 + } \ 1.187 + } \ 1.188 + return NS_OK; \ 1.189 + } \ 1.190 + } \ 1.191 + nsresult rv = originPrincipal->GetURI(getter_AddRefs(requestOrigin)); \ 1.192 + NS_ENSURE_SUCCESS(rv, rv); \ 1.193 + } \ 1.194 + PR_END_MACRO 1.195 + 1.196 +/** 1.197 + * Alias for calling ShouldLoad on the content policy service. Parameters are 1.198 + * the same as nsIContentPolicy::shouldLoad, except for the originPrincipal 1.199 + * parameter, which should be non-null if possible, and the last two 1.200 + * parameters, which can be used to pass in pointer to some useful services if 1.201 + * the caller already has them. The origin URI to pass to shouldLoad will be 1.202 + * the URI of originPrincipal, unless originPrincipal is null (in which case a 1.203 + * null origin URI will be passed). 1.204 + */ 1.205 +inline nsresult 1.206 +NS_CheckContentLoadPolicy(uint32_t contentType, 1.207 + nsIURI *contentLocation, 1.208 + nsIPrincipal *originPrincipal, 1.209 + nsISupports *context, 1.210 + const nsACString &mimeType, 1.211 + nsISupports *extra, 1.212 + int16_t *decision, 1.213 + nsIContentPolicy *policyService = nullptr, 1.214 + nsIScriptSecurityManager* aSecMan = nullptr) 1.215 +{ 1.216 + CHECK_PRINCIPAL_AND_DATA(ShouldLoad); 1.217 + if (policyService) { 1.218 + CHECK_CONTENT_POLICY_WITH_SERVICE(ShouldLoad, policyService); 1.219 + } 1.220 + CHECK_CONTENT_POLICY(ShouldLoad); 1.221 +} 1.222 + 1.223 +/** 1.224 + * Alias for calling ShouldProcess on the content policy service. Parameters 1.225 + * are the same as nsIContentPolicy::shouldLoad, except for the originPrincipal 1.226 + * parameter, which should be non-null if possible, and the last two 1.227 + * parameters, which can be used to pass in pointer to some useful services if 1.228 + * the caller already has them. The origin URI to pass to shouldLoad will be 1.229 + * the URI of originPrincipal, unless originPrincipal is null (in which case a 1.230 + * null origin URI will be passed). 1.231 + */ 1.232 +inline nsresult 1.233 +NS_CheckContentProcessPolicy(uint32_t contentType, 1.234 + nsIURI *contentLocation, 1.235 + nsIPrincipal *originPrincipal, 1.236 + nsISupports *context, 1.237 + const nsACString &mimeType, 1.238 + nsISupports *extra, 1.239 + int16_t *decision, 1.240 + nsIContentPolicy *policyService = nullptr, 1.241 + nsIScriptSecurityManager* aSecMan = nullptr) 1.242 +{ 1.243 + CHECK_PRINCIPAL_AND_DATA(ShouldProcess); 1.244 + if (policyService) { 1.245 + CHECK_CONTENT_POLICY_WITH_SERVICE(ShouldProcess, policyService); 1.246 + } 1.247 + CHECK_CONTENT_POLICY(ShouldProcess); 1.248 +} 1.249 + 1.250 +#undef CHECK_CONTENT_POLICY 1.251 +#undef CHECK_CONTENT_POLICY_WITH_SERVICE 1.252 + 1.253 +/** 1.254 + * Helper function to get an nsIDocShell given a context. 1.255 + * If the context is a document or window, the corresponding docshell will be 1.256 + * returned. 1.257 + * If the context is a non-document DOM node, the docshell of its ownerDocument 1.258 + * will be returned. 1.259 + * 1.260 + * @param aContext the context to find a docshell for (can be null) 1.261 + * 1.262 + * @return a WEAK pointer to the docshell, or nullptr if it could 1.263 + * not be obtained 1.264 + * 1.265 + * @note As of this writing, calls to nsIContentPolicy::Should{Load,Process} 1.266 + * for TYPE_DOCUMENT and TYPE_SUBDOCUMENT pass in an aContext that either 1.267 + * points to the frameElement of the window the load is happening in 1.268 + * (in which case NS_CP_GetDocShellFromContext will return the parent of the 1.269 + * docshell the load is happening in), or points to the window the load is 1.270 + * happening in (in which case NS_CP_GetDocShellFromContext will return 1.271 + * the docshell the load is happening in). It's up to callers to QI aContext 1.272 + * and handle things accordingly if they want the docshell the load is 1.273 + * happening in. These are somewhat odd semantics, and bug 466687 has been 1.274 + * filed to consider improving them. 1.275 + */ 1.276 +inline nsIDocShell* 1.277 +NS_CP_GetDocShellFromContext(nsISupports *aContext) 1.278 +{ 1.279 + if (!aContext) { 1.280 + return nullptr; 1.281 + } 1.282 + 1.283 + nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aContext); 1.284 + 1.285 + if (!window) { 1.286 + // our context might be a document (which also QIs to nsIDOMNode), so 1.287 + // try that first 1.288 + nsCOMPtr<nsIDocument> doc = do_QueryInterface(aContext); 1.289 + if (!doc) { 1.290 + // we were not a document after all, get our ownerDocument, 1.291 + // hopefully 1.292 + nsCOMPtr<nsIContent> content = do_QueryInterface(aContext); 1.293 + if (content) { 1.294 + doc = content->OwnerDoc(); 1.295 + } 1.296 + } 1.297 + 1.298 + if (doc) { 1.299 + if (doc->GetDisplayDocument()) { 1.300 + doc = doc->GetDisplayDocument(); 1.301 + } 1.302 + 1.303 + window = doc->GetWindow(); 1.304 + } 1.305 + } 1.306 + 1.307 + if (!window) { 1.308 + return nullptr; 1.309 + } 1.310 + 1.311 + return window->GetDocShell(); 1.312 +} 1.313 + 1.314 +#endif /* __nsContentPolicyUtils_h__ */