1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : // vim: ft=cpp tw=78 sw=4 et ts=8
3 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is Mozilla code.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Zero-Knowledge Systems, Inc.
20 : * Portions created by the Initial Developer are Copyright (C) 2000
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either of the GNU General Public License Version 2 or later (the "GPL"),
27 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : /*
40 : * Implementation of the "@mozilla.org/layout/content-policy;1" contract.
41 : */
42 :
43 : #include "prlog.h"
44 :
45 : #include "nsISupports.h"
46 : #include "nsXPCOM.h"
47 : #include "nsContentPolicyUtils.h"
48 : #include "nsContentPolicy.h"
49 : #include "nsIURI.h"
50 : #include "nsIDOMNode.h"
51 : #include "nsIDOMWindow.h"
52 : #include "nsIContent.h"
53 : #include "nsCOMArray.h"
54 :
55 1052 : NS_IMPL_ISUPPORTS1(nsContentPolicy, nsIContentPolicy)
56 :
57 : #ifdef PR_LOGGING
58 : static PRLogModuleInfo* gConPolLog;
59 : #endif
60 :
61 : nsresult
62 113 : NS_NewContentPolicy(nsIContentPolicy **aResult)
63 : {
64 113 : *aResult = new nsContentPolicy;
65 113 : if (!*aResult)
66 0 : return NS_ERROR_OUT_OF_MEMORY;
67 113 : NS_ADDREF(*aResult);
68 113 : return NS_OK;
69 : }
70 :
71 113 : nsContentPolicy::nsContentPolicy()
72 113 : : mPolicies(NS_CONTENTPOLICY_CATEGORY)
73 : {
74 : #ifdef PR_LOGGING
75 113 : if (! gConPolLog) {
76 113 : gConPolLog = PR_NewLogModule("nsContentPolicy");
77 : }
78 : #endif
79 113 : }
80 :
81 226 : nsContentPolicy::~nsContentPolicy()
82 : {
83 452 : }
84 :
85 : #ifdef DEBUG
86 : #define WARN_IF_URI_UNINITIALIZED(uri,name) \
87 : PR_BEGIN_MACRO \
88 : if ((uri)) { \
89 : nsCAutoString spec; \
90 : (uri)->GetAsciiSpec(spec); \
91 : if (spec.IsEmpty()) { \
92 : NS_WARNING(name " is uninitialized, fix caller"); \
93 : } \
94 : } \
95 : PR_END_MACRO
96 :
97 : #else // ! defined(DEBUG)
98 :
99 : #define WARN_IF_URI_UNINITIALIZED(uri,name)
100 :
101 : #endif // defined(DEBUG)
102 :
103 : inline nsresult
104 10 : nsContentPolicy::CheckPolicy(CPMethod policyMethod,
105 : PRUint32 contentType,
106 : nsIURI *contentLocation,
107 : nsIURI *requestingLocation,
108 : nsISupports *requestingContext,
109 : const nsACString &mimeType,
110 : nsISupports *extra,
111 : PRInt16 *decision)
112 : {
113 : //sanity-check passed-through parameters
114 10 : NS_PRECONDITION(decision, "Null out pointer");
115 10 : WARN_IF_URI_UNINITIALIZED(contentLocation, "Request URI");
116 10 : WARN_IF_URI_UNINITIALIZED(requestingLocation, "Requesting URI");
117 :
118 : #ifdef DEBUG
119 : {
120 20 : nsCOMPtr<nsIDOMNode> node(do_QueryInterface(requestingContext));
121 20 : nsCOMPtr<nsIDOMWindow> window(do_QueryInterface(requestingContext));
122 10 : NS_ASSERTION(!requestingContext || node || window,
123 : "Context should be a DOM node or a DOM window!");
124 : }
125 : #endif
126 :
127 : /*
128 : * There might not be a requestinglocation. This can happen for
129 : * iframes with an image as src. Get the uri from the dom node.
130 : * See bug 254510
131 : */
132 10 : if (!requestingLocation) {
133 4 : nsCOMPtr<nsIDocument> doc;
134 4 : nsCOMPtr<nsIContent> node = do_QueryInterface(requestingContext);
135 2 : if (node) {
136 0 : doc = node->OwnerDoc();
137 : }
138 2 : if (!doc) {
139 2 : doc = do_QueryInterface(requestingContext);
140 : }
141 2 : if (doc) {
142 0 : requestingLocation = doc->GetDocumentURI();
143 : }
144 : }
145 :
146 : /*
147 : * Enumerate mPolicies and ask each of them, taking the logical AND of
148 : * their permissions.
149 : */
150 : nsresult rv;
151 10 : const nsCOMArray<nsIContentPolicy>& entries = mPolicies.GetEntries();
152 10 : PRInt32 count = entries.Count();
153 60 : for (PRInt32 i = 0; i < count; i++) {
154 : /* check the appropriate policy */
155 50 : rv = (entries[i]->*policyMethod)(contentType, contentLocation,
156 : requestingLocation, requestingContext,
157 50 : mimeType, extra, decision);
158 :
159 50 : if (NS_SUCCEEDED(rv) && NS_CP_REJECTED(*decision)) {
160 : /* policy says no, no point continuing to check */
161 0 : return NS_OK;
162 : }
163 : }
164 :
165 : // everyone returned failure, or no policies: sanitize result
166 10 : *decision = nsIContentPolicy::ACCEPT;
167 10 : return NS_OK;
168 : }
169 :
170 : #ifdef PR_LOGGING
171 :
172 : //uses the parameters from ShouldXYZ to produce and log a message
173 : //logType must be a literal string constant
174 : #define LOG_CHECK(logType) \
175 : PR_BEGIN_MACRO \
176 : /* skip all this nonsense if the call failed */ \
177 : if (NS_SUCCEEDED(rv)) { \
178 : const char *resultName; \
179 : if (decision) { \
180 : resultName = NS_CP_ResponseName(*decision); \
181 : } else { \
182 : resultName = "(null ptr)"; \
183 : } \
184 : nsCAutoString spec("None"); \
185 : if (contentLocation) { \
186 : contentLocation->GetSpec(spec); \
187 : } \
188 : nsCAutoString refSpec("None"); \
189 : if (requestingLocation) { \
190 : requestingLocation->GetSpec(refSpec); \
191 : } \
192 : PR_LOG(gConPolLog, PR_LOG_DEBUG, \
193 : ("Content Policy: " logType ": <%s> <Ref:%s> result=%s", \
194 : spec.get(), refSpec.get(), resultName) \
195 : ); \
196 : } \
197 : PR_END_MACRO
198 :
199 : #else //!defined(PR_LOGGING)
200 :
201 : #define LOG_CHECK(logType)
202 :
203 : #endif //!defined(PR_LOGGING)
204 :
205 : NS_IMETHODIMP
206 10 : nsContentPolicy::ShouldLoad(PRUint32 contentType,
207 : nsIURI *contentLocation,
208 : nsIURI *requestingLocation,
209 : nsISupports *requestingContext,
210 : const nsACString &mimeType,
211 : nsISupports *extra,
212 : PRInt16 *decision)
213 : {
214 : // ShouldProcess does not need a content location, but we do
215 10 : NS_PRECONDITION(contentLocation, "Must provide request location");
216 : nsresult rv = CheckPolicy(&nsIContentPolicy::ShouldLoad, contentType,
217 : contentLocation, requestingLocation,
218 10 : requestingContext, mimeType, extra, decision);
219 10 : LOG_CHECK("ShouldLoad");
220 :
221 10 : return rv;
222 : }
223 :
224 : NS_IMETHODIMP
225 0 : nsContentPolicy::ShouldProcess(PRUint32 contentType,
226 : nsIURI *contentLocation,
227 : nsIURI *requestingLocation,
228 : nsISupports *requestingContext,
229 : const nsACString &mimeType,
230 : nsISupports *extra,
231 : PRInt16 *decision)
232 : {
233 : nsresult rv = CheckPolicy(&nsIContentPolicy::ShouldProcess, contentType,
234 : contentLocation, requestingLocation,
235 0 : requestingContext, mimeType, extra, decision);
236 0 : LOG_CHECK("ShouldProcess");
237 :
238 0 : return rv;
239 : }
|