1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 * Utility routines for checking content load/process policy settings,
8 * and routines helpful for content policy implementors.
10 * XXXbz it would be nice if some of this stuff could be out-of-lined in
11 * nsContentUtils. That would work for almost all the callers...
14 #ifndef __nsContentPolicyUtils_h__
15 #define __nsContentPolicyUtils_h__
17 #include "mozilla/BasePrincipal.h"
19 #include "nsContentUtils.h"
20 #include "nsIContentPolicy.h"
21 #include "nsIContent.h"
22 #include "nsIScriptSecurityManager.h"
24 #include "nsServiceManagerUtils.h"
25 #include "nsStringFwd.h"
26 #include "mozilla/dom/nsCSPService.h"
28 // XXXtw sadly, this makes consumers of nsContentPolicyUtils depend on widget
29 #include "mozilla/dom/Document.h"
30 #include "nsPIDOMWindow.h"
32 #define NS_CONTENTPOLICY_CONTRACTID "@mozilla.org/layout/content-policy;1"
33 #define NS_CONTENTPOLICY_CATEGORY "content-policy"
34 #define NS_CONTENTPOLICY_CID \
36 0x0e3afd3d, 0xeb60, 0x4c2b, { \
37 0x96, 0x3b, 0x56, 0xd7, 0xc4, 0x39, 0xf1, 0x24 \
42 * Evaluates to true if val is ACCEPT.
44 * @param val the status returned from shouldProcess/shouldLoad
46 #define NS_CP_ACCEPTED(val) ((val) == nsIContentPolicy::ACCEPT)
49 * Evaluates to true if val is a REJECT_* status
51 * @param val the status returned from shouldProcess/shouldLoad
53 #define NS_CP_REJECTED(val) ((val) != nsIContentPolicy::ACCEPT)
55 // Offer convenient translations of constants -> const char*
57 // convenience macro to reduce some repetative typing...
58 // name is the name of a constant from this interface
59 #define CASE_RETURN(name) \
60 case nsIContentPolicy::name: \
64 * Returns a string corresponding to the name of the response constant, or
65 * "<Unknown Response>" if an unknown response value is given.
67 * The return value is static and must not be freed.
69 * @param response the response code
70 * @return the name of the given response code
72 inline const char* NS_CP_ResponseName(int16_t response
) {
74 CASE_RETURN(REJECT_REQUEST
);
75 CASE_RETURN(REJECT_TYPE
);
76 CASE_RETURN(REJECT_SERVER
);
77 CASE_RETURN(REJECT_OTHER
);
80 return "<Unknown Response>";
85 * Returns a string corresponding to the name of the content type constant, or
86 * "<Unknown Type>" if an unknown content type value is given.
88 * The return value is static and must not be freed.
90 * @param contentType the content type code
91 * @return the name of the given content type code
93 inline const char* NS_CP_ContentTypeName(uint32_t contentType
) {
94 switch (contentType
) {
95 CASE_RETURN(TYPE_OTHER
);
96 CASE_RETURN(TYPE_SCRIPT
);
97 CASE_RETURN(TYPE_IMAGE
);
98 CASE_RETURN(TYPE_STYLESHEET
);
99 CASE_RETURN(TYPE_OBJECT
);
100 CASE_RETURN(TYPE_DOCUMENT
);
101 CASE_RETURN(TYPE_SUBDOCUMENT
);
102 CASE_RETURN(TYPE_REFRESH
);
103 CASE_RETURN(TYPE_XBL
);
104 CASE_RETURN(TYPE_PING
);
105 CASE_RETURN(TYPE_XMLHTTPREQUEST
);
106 CASE_RETURN(TYPE_OBJECT_SUBREQUEST
);
107 CASE_RETURN(TYPE_DTD
);
108 CASE_RETURN(TYPE_FONT
);
109 CASE_RETURN(TYPE_MEDIA
);
110 CASE_RETURN(TYPE_WEBSOCKET
);
111 CASE_RETURN(TYPE_CSP_REPORT
);
112 CASE_RETURN(TYPE_XSLT
);
113 CASE_RETURN(TYPE_BEACON
);
114 CASE_RETURN(TYPE_FETCH
);
115 CASE_RETURN(TYPE_IMAGESET
);
116 CASE_RETURN(TYPE_WEB_MANIFEST
);
117 CASE_RETURN(TYPE_INTERNAL_SCRIPT
);
118 CASE_RETURN(TYPE_INTERNAL_WORKER
);
119 CASE_RETURN(TYPE_INTERNAL_SHARED_WORKER
);
120 CASE_RETURN(TYPE_INTERNAL_EMBED
);
121 CASE_RETURN(TYPE_INTERNAL_OBJECT
);
122 CASE_RETURN(TYPE_INTERNAL_FRAME
);
123 CASE_RETURN(TYPE_INTERNAL_IFRAME
);
124 CASE_RETURN(TYPE_INTERNAL_AUDIO
);
125 CASE_RETURN(TYPE_INTERNAL_VIDEO
);
126 CASE_RETURN(TYPE_INTERNAL_TRACK
);
127 CASE_RETURN(TYPE_INTERNAL_XMLHTTPREQUEST
);
128 CASE_RETURN(TYPE_INTERNAL_EVENTSOURCE
);
129 CASE_RETURN(TYPE_INTERNAL_SERVICE_WORKER
);
130 CASE_RETURN(TYPE_INTERNAL_SCRIPT_PRELOAD
);
131 CASE_RETURN(TYPE_INTERNAL_IMAGE
);
132 CASE_RETURN(TYPE_INTERNAL_IMAGE_PRELOAD
);
133 CASE_RETURN(TYPE_INTERNAL_IMAGE_FAVICON
);
134 CASE_RETURN(TYPE_INTERNAL_STYLESHEET
);
135 CASE_RETURN(TYPE_INTERNAL_STYLESHEET_PRELOAD
);
136 CASE_RETURN(TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS
);
137 CASE_RETURN(TYPE_SAVEAS_DOWNLOAD
);
138 CASE_RETURN(TYPE_SPECULATIVE
);
139 CASE_RETURN(TYPE_INTERNAL_MODULE
);
140 CASE_RETURN(TYPE_INTERNAL_MODULE_PRELOAD
);
142 return "<Unknown Type>";
148 /* Passes on parameters from its "caller"'s context. */
149 #define CHECK_CONTENT_POLICY(action) \
151 nsCOMPtr<nsIContentPolicy> policy = \
152 do_GetService(NS_CONTENTPOLICY_CONTRACTID); \
153 if (!policy) return NS_ERROR_FAILURE; \
155 return policy->action(contentLocation, loadInfo, mimeType, decision); \
158 /* Passes on parameters from its "caller"'s context. */
159 #define CHECK_CONTENT_POLICY_WITH_SERVICE(action, _policy) \
161 return _policy->action(contentLocation, loadInfo, mimeType, decision); \
165 * Check whether we can short-circuit this check and bail out. If not, get the
168 * Note: requestOrigin is scoped outside the PR_BEGIN_MACRO/PR_END_MACRO on
170 #define CHECK_PRINCIPAL_CSP_AND_DATA(action) \
171 nsCOMPtr<nsIURI> requestOrigin; \
173 if (loadingPrincipal) { \
174 /* We exempt most loads into any document with the system principal \
175 * from content policy (escept CSP) checks, mostly as an optimization. \
176 * Which means that we need to apply this check to the loading principal, \
177 * not the principal that triggered the load. */ \
178 bool isSystem = loadingPrincipal->IsSystemPrincipal(); \
180 /* Check CSP for System Privileged pages */ \
181 CSPService::ConsultCSP(contentLocation, loadInfo, mimeType, decision); \
182 if (NS_CP_REJECTED(*decision)) { \
185 if (contentType != nsIContentPolicy::TYPE_DOCUMENT) { \
186 *decision = nsIContentPolicy::ACCEPT; \
187 nsCOMPtr<nsINode> n = do_QueryInterface(context); \
189 nsCOMPtr<nsPIDOMWindowOuter> win = do_QueryInterface(context); \
190 n = win ? win->GetExtantDoc() : nullptr; \
193 mozilla::dom::Document* d = n->OwnerDoc(); \
194 if (d->IsLoadedAsData() || d->IsBeingUsedAsImage() || \
195 d->IsResourceDoc()) { \
196 nsCOMPtr<nsIContentPolicy> dataPolicy = \
197 do_GetService("@mozilla.org/data-document-content-policy;1"); \
199 dataPolicy->action(contentLocation, loadInfo, mimeType, \
207 nsresult rv = loadingPrincipal->GetURI(getter_AddRefs(requestOrigin)); \
208 NS_ENSURE_SUCCESS(rv, rv); \
213 * Alias for calling ShouldLoad on the content policy service. Parameters are
214 * the same as nsIContentPolicy::shouldLoad, except for the loadingPrincipal
215 * and triggeringPrincipal parameters (which should be non-null if possible,
216 * and have the same semantics as in nsLoadInfo), and the last parameter,
217 * which can be used to pass in a pointer to a useful service if the caller
218 * already has it. The origin URI to pass to shouldLoad will be the URI of
219 * loadingPrincipal, unless loadingPrincipal is null (in which case a null
220 * origin URI will be passed).
222 inline nsresult
NS_CheckContentLoadPolicy(
223 nsIURI
* contentLocation
, nsILoadInfo
* loadInfo
, const nsACString
& mimeType
,
224 int16_t* decision
, nsIContentPolicy
* policyService
= nullptr) {
225 nsIPrincipal
* loadingPrincipal
= loadInfo
->LoadingPrincipal();
226 nsCOMPtr
<nsISupports
> context
= loadInfo
->GetLoadingContext();
227 nsContentPolicyType contentType
= loadInfo
->InternalContentPolicyType();
228 CHECK_PRINCIPAL_CSP_AND_DATA(ShouldLoad
);
230 CHECK_CONTENT_POLICY_WITH_SERVICE(ShouldLoad
, policyService
);
232 CHECK_CONTENT_POLICY(ShouldLoad
);
236 * Alias for calling ShouldProcess on the content policy service.
238 inline nsresult
NS_CheckContentProcessPolicy(
239 nsIURI
* contentLocation
, nsILoadInfo
* loadInfo
, const nsACString
& mimeType
,
240 int16_t* decision
, nsIContentPolicy
* policyService
= nullptr) {
241 nsIPrincipal
* loadingPrincipal
= loadInfo
->LoadingPrincipal();
242 nsCOMPtr
<nsISupports
> context
= loadInfo
->GetLoadingContext();
243 nsContentPolicyType contentType
= loadInfo
->InternalContentPolicyType();
244 CHECK_PRINCIPAL_CSP_AND_DATA(ShouldProcess
);
246 CHECK_CONTENT_POLICY_WITH_SERVICE(ShouldProcess
, policyService
);
248 CHECK_CONTENT_POLICY(ShouldProcess
);
251 #undef CHECK_CONTENT_POLICY
252 #undef CHECK_CONTENT_POLICY_WITH_SERVICE
255 * Helper function to get an nsIDocShell given a context.
256 * If the context is a document or window, the corresponding docshell will be
258 * If the context is a non-document DOM node, the docshell of its ownerDocument
261 * @param aContext the context to find a docshell for (can be null)
263 * @return a WEAK pointer to the docshell, or nullptr if it could
266 * @note As of this writing, calls to nsIContentPolicy::Should{Load,Process}
267 * for TYPE_DOCUMENT and TYPE_SUBDOCUMENT pass in an aContext that either
268 * points to the frameElement of the window the load is happening in
269 * (in which case NS_CP_GetDocShellFromContext will return the parent of the
270 * docshell the load is happening in), or points to the window the load is
271 * happening in (in which case NS_CP_GetDocShellFromContext will return
272 * the docshell the load is happening in). It's up to callers to QI aContext
273 * and handle things accordingly if they want the docshell the load is
274 * happening in. These are somewhat odd semantics, and bug 466687 has been
275 * filed to consider improving them.
277 inline nsIDocShell
* NS_CP_GetDocShellFromContext(nsISupports
* aContext
) {
282 nsCOMPtr
<nsPIDOMWindowOuter
> window
= do_QueryInterface(aContext
);
285 // Our context might be a document.
286 nsCOMPtr
<mozilla::dom::Document
> doc
= do_QueryInterface(aContext
);
288 // we were not a document after all, get our ownerDocument,
290 nsCOMPtr
<nsIContent
> content
= do_QueryInterface(aContext
);
292 doc
= content
->OwnerDoc();
297 if (doc
->GetDisplayDocument()) {
298 doc
= doc
->GetDisplayDocument();
301 window
= doc
->GetWindow();
309 return window
->GetDocShell();
312 #endif /* __nsContentPolicyUtils_h__ */