|
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
|
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/. */ |
|
5 |
|
6 /* |
|
7 * Utility routines for checking content load/process policy settings, |
|
8 * and routines helpful for content policy implementors. |
|
9 * |
|
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... |
|
12 */ |
|
13 |
|
14 #ifndef __nsContentPolicyUtils_h__ |
|
15 #define __nsContentPolicyUtils_h__ |
|
16 |
|
17 #include "nsIContentPolicy.h" |
|
18 #include "nsIContent.h" |
|
19 #include "nsIScriptSecurityManager.h" |
|
20 #include "nsIURI.h" |
|
21 #include "nsServiceManagerUtils.h" |
|
22 |
|
23 //XXXtw sadly, this makes consumers of nsContentPolicyUtils depend on widget |
|
24 #include "nsIDocument.h" |
|
25 #include "nsPIDOMWindow.h" |
|
26 |
|
27 class nsACString; |
|
28 class nsIPrincipal; |
|
29 |
|
30 #define NS_CONTENTPOLICY_CONTRACTID "@mozilla.org/layout/content-policy;1" |
|
31 #define NS_CONTENTPOLICY_CATEGORY "content-policy" |
|
32 #define NS_CONTENTPOLICY_CID \ |
|
33 {0x0e3afd3d, 0xeb60, 0x4c2b, \ |
|
34 { 0x96, 0x3b, 0x56, 0xd7, 0xc4, 0x39, 0xf1, 0x24 }} |
|
35 |
|
36 /** |
|
37 * Evaluates to true if val is ACCEPT. |
|
38 * |
|
39 * @param val the status returned from shouldProcess/shouldLoad |
|
40 */ |
|
41 #define NS_CP_ACCEPTED(val) ((val) == nsIContentPolicy::ACCEPT) |
|
42 |
|
43 /** |
|
44 * Evaluates to true if val is a REJECT_* status |
|
45 * |
|
46 * @param val the status returned from shouldProcess/shouldLoad |
|
47 */ |
|
48 #define NS_CP_REJECTED(val) ((val) != nsIContentPolicy::ACCEPT) |
|
49 |
|
50 // Offer convenient translations of constants -> const char* |
|
51 |
|
52 // convenience macro to reduce some repetative typing... |
|
53 // name is the name of a constant from this interface |
|
54 #define CASE_RETURN(name) \ |
|
55 case nsIContentPolicy:: name : \ |
|
56 return #name |
|
57 |
|
58 #ifdef PR_LOGGING |
|
59 /** |
|
60 * Returns a string corresponding to the name of the response constant, or |
|
61 * "<Unknown Response>" if an unknown response value is given. |
|
62 * |
|
63 * The return value is static and must not be freed. |
|
64 * |
|
65 * @param response the response code |
|
66 * @return the name of the given response code |
|
67 */ |
|
68 inline const char * |
|
69 NS_CP_ResponseName(int16_t response) |
|
70 { |
|
71 switch (response) { |
|
72 CASE_RETURN( REJECT_REQUEST ); |
|
73 CASE_RETURN( REJECT_TYPE ); |
|
74 CASE_RETURN( REJECT_SERVER ); |
|
75 CASE_RETURN( REJECT_OTHER ); |
|
76 CASE_RETURN( ACCEPT ); |
|
77 default: |
|
78 return "<Unknown Response>"; |
|
79 } |
|
80 } |
|
81 |
|
82 /** |
|
83 * Returns a string corresponding to the name of the content type constant, or |
|
84 * "<Unknown Type>" if an unknown content type value is given. |
|
85 * |
|
86 * The return value is static and must not be freed. |
|
87 * |
|
88 * @param contentType the content type code |
|
89 * @return the name of the given content type code |
|
90 */ |
|
91 inline const char * |
|
92 NS_CP_ContentTypeName(uint32_t contentType) |
|
93 { |
|
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 default: |
|
115 return "<Unknown Type>"; |
|
116 } |
|
117 } |
|
118 |
|
119 #endif // defined(PR_LOGGING) |
|
120 |
|
121 #undef CASE_RETURN |
|
122 |
|
123 /* Passes on parameters from its "caller"'s context. */ |
|
124 #define CHECK_CONTENT_POLICY(action) \ |
|
125 PR_BEGIN_MACRO \ |
|
126 nsCOMPtr<nsIContentPolicy> policy = \ |
|
127 do_GetService(NS_CONTENTPOLICY_CONTRACTID); \ |
|
128 if (!policy) \ |
|
129 return NS_ERROR_FAILURE; \ |
|
130 \ |
|
131 return policy-> action (contentType, contentLocation, requestOrigin, \ |
|
132 context, mimeType, extra, originPrincipal, \ |
|
133 decision); \ |
|
134 PR_END_MACRO |
|
135 |
|
136 /* Passes on parameters from its "caller"'s context. */ |
|
137 #define CHECK_CONTENT_POLICY_WITH_SERVICE(action, _policy) \ |
|
138 PR_BEGIN_MACRO \ |
|
139 return _policy-> action (contentType, contentLocation, requestOrigin, \ |
|
140 context, mimeType, extra, originPrincipal, \ |
|
141 decision); \ |
|
142 PR_END_MACRO |
|
143 |
|
144 /** |
|
145 * Check whether we can short-circuit this check and bail out. If not, get the |
|
146 * origin URI to use. |
|
147 * |
|
148 * Note: requestOrigin is scoped outside the PR_BEGIN_MACRO/PR_END_MACRO on |
|
149 * purpose */ |
|
150 #define CHECK_PRINCIPAL_AND_DATA(action) \ |
|
151 nsCOMPtr<nsIURI> requestOrigin; \ |
|
152 PR_BEGIN_MACRO \ |
|
153 if (originPrincipal) { \ |
|
154 nsCOMPtr<nsIScriptSecurityManager> secMan = aSecMan; \ |
|
155 if (!secMan) { \ |
|
156 secMan = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID); \ |
|
157 } \ |
|
158 if (secMan) { \ |
|
159 bool isSystem; \ |
|
160 nsresult rv = secMan->IsSystemPrincipal(originPrincipal, \ |
|
161 &isSystem); \ |
|
162 NS_ENSURE_SUCCESS(rv, rv); \ |
|
163 if (isSystem) { \ |
|
164 *decision = nsIContentPolicy::ACCEPT; \ |
|
165 nsCOMPtr<nsINode> n = do_QueryInterface(context); \ |
|
166 if (!n) { \ |
|
167 nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(context); \ |
|
168 n = win ? win->GetExtantDoc() : nullptr; \ |
|
169 } \ |
|
170 if (n) { \ |
|
171 nsIDocument* d = n->OwnerDoc(); \ |
|
172 if (d->IsLoadedAsData() || d->IsBeingUsedAsImage() || \ |
|
173 d->IsResourceDoc()) { \ |
|
174 nsCOMPtr<nsIContentPolicy> dataPolicy = \ |
|
175 do_GetService( \ |
|
176 "@mozilla.org/data-document-content-policy;1"); \ |
|
177 if (dataPolicy) { \ |
|
178 dataPolicy-> action (contentType, contentLocation, \ |
|
179 requestOrigin, context, \ |
|
180 mimeType, extra, \ |
|
181 originPrincipal, decision); \ |
|
182 } \ |
|
183 } \ |
|
184 } \ |
|
185 return NS_OK; \ |
|
186 } \ |
|
187 } \ |
|
188 nsresult rv = originPrincipal->GetURI(getter_AddRefs(requestOrigin)); \ |
|
189 NS_ENSURE_SUCCESS(rv, rv); \ |
|
190 } \ |
|
191 PR_END_MACRO |
|
192 |
|
193 /** |
|
194 * Alias for calling ShouldLoad on the content policy service. Parameters are |
|
195 * the same as nsIContentPolicy::shouldLoad, except for the originPrincipal |
|
196 * parameter, which should be non-null if possible, and the last two |
|
197 * parameters, which can be used to pass in pointer to some useful services if |
|
198 * the caller already has them. The origin URI to pass to shouldLoad will be |
|
199 * the URI of originPrincipal, unless originPrincipal is null (in which case a |
|
200 * null origin URI will be passed). |
|
201 */ |
|
202 inline nsresult |
|
203 NS_CheckContentLoadPolicy(uint32_t contentType, |
|
204 nsIURI *contentLocation, |
|
205 nsIPrincipal *originPrincipal, |
|
206 nsISupports *context, |
|
207 const nsACString &mimeType, |
|
208 nsISupports *extra, |
|
209 int16_t *decision, |
|
210 nsIContentPolicy *policyService = nullptr, |
|
211 nsIScriptSecurityManager* aSecMan = nullptr) |
|
212 { |
|
213 CHECK_PRINCIPAL_AND_DATA(ShouldLoad); |
|
214 if (policyService) { |
|
215 CHECK_CONTENT_POLICY_WITH_SERVICE(ShouldLoad, policyService); |
|
216 } |
|
217 CHECK_CONTENT_POLICY(ShouldLoad); |
|
218 } |
|
219 |
|
220 /** |
|
221 * Alias for calling ShouldProcess on the content policy service. Parameters |
|
222 * are the same as nsIContentPolicy::shouldLoad, except for the originPrincipal |
|
223 * parameter, which should be non-null if possible, and the last two |
|
224 * parameters, which can be used to pass in pointer to some useful services if |
|
225 * the caller already has them. The origin URI to pass to shouldLoad will be |
|
226 * the URI of originPrincipal, unless originPrincipal is null (in which case a |
|
227 * null origin URI will be passed). |
|
228 */ |
|
229 inline nsresult |
|
230 NS_CheckContentProcessPolicy(uint32_t contentType, |
|
231 nsIURI *contentLocation, |
|
232 nsIPrincipal *originPrincipal, |
|
233 nsISupports *context, |
|
234 const nsACString &mimeType, |
|
235 nsISupports *extra, |
|
236 int16_t *decision, |
|
237 nsIContentPolicy *policyService = nullptr, |
|
238 nsIScriptSecurityManager* aSecMan = nullptr) |
|
239 { |
|
240 CHECK_PRINCIPAL_AND_DATA(ShouldProcess); |
|
241 if (policyService) { |
|
242 CHECK_CONTENT_POLICY_WITH_SERVICE(ShouldProcess, policyService); |
|
243 } |
|
244 CHECK_CONTENT_POLICY(ShouldProcess); |
|
245 } |
|
246 |
|
247 #undef CHECK_CONTENT_POLICY |
|
248 #undef CHECK_CONTENT_POLICY_WITH_SERVICE |
|
249 |
|
250 /** |
|
251 * Helper function to get an nsIDocShell given a context. |
|
252 * If the context is a document or window, the corresponding docshell will be |
|
253 * returned. |
|
254 * If the context is a non-document DOM node, the docshell of its ownerDocument |
|
255 * will be returned. |
|
256 * |
|
257 * @param aContext the context to find a docshell for (can be null) |
|
258 * |
|
259 * @return a WEAK pointer to the docshell, or nullptr if it could |
|
260 * not be obtained |
|
261 * |
|
262 * @note As of this writing, calls to nsIContentPolicy::Should{Load,Process} |
|
263 * for TYPE_DOCUMENT and TYPE_SUBDOCUMENT pass in an aContext that either |
|
264 * points to the frameElement of the window the load is happening in |
|
265 * (in which case NS_CP_GetDocShellFromContext will return the parent of the |
|
266 * docshell the load is happening in), or points to the window the load is |
|
267 * happening in (in which case NS_CP_GetDocShellFromContext will return |
|
268 * the docshell the load is happening in). It's up to callers to QI aContext |
|
269 * and handle things accordingly if they want the docshell the load is |
|
270 * happening in. These are somewhat odd semantics, and bug 466687 has been |
|
271 * filed to consider improving them. |
|
272 */ |
|
273 inline nsIDocShell* |
|
274 NS_CP_GetDocShellFromContext(nsISupports *aContext) |
|
275 { |
|
276 if (!aContext) { |
|
277 return nullptr; |
|
278 } |
|
279 |
|
280 nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aContext); |
|
281 |
|
282 if (!window) { |
|
283 // our context might be a document (which also QIs to nsIDOMNode), so |
|
284 // try that first |
|
285 nsCOMPtr<nsIDocument> doc = do_QueryInterface(aContext); |
|
286 if (!doc) { |
|
287 // we were not a document after all, get our ownerDocument, |
|
288 // hopefully |
|
289 nsCOMPtr<nsIContent> content = do_QueryInterface(aContext); |
|
290 if (content) { |
|
291 doc = content->OwnerDoc(); |
|
292 } |
|
293 } |
|
294 |
|
295 if (doc) { |
|
296 if (doc->GetDisplayDocument()) { |
|
297 doc = doc->GetDisplayDocument(); |
|
298 } |
|
299 |
|
300 window = doc->GetWindow(); |
|
301 } |
|
302 } |
|
303 |
|
304 if (!window) { |
|
305 return nullptr; |
|
306 } |
|
307 |
|
308 return window->GetDocShell(); |
|
309 } |
|
310 |
|
311 #endif /* __nsContentPolicyUtils_h__ */ |