Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / xpinstall / src / nsXPITriggerInfo.cpp
blobe5183a8c3afb94d42037c0d5d9683c304018eaa3
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is Mozilla Communicator client code, released
16 * March 31, 1998.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998-1999
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
24 * Daniel Veditz <dveditz@netscape.com>
25 * Dave Townsend <dtownsend@oxymoronical.com>
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
41 #include "nscore.h"
42 #include "plstr.h"
43 #include "nsXPITriggerInfo.h"
44 #include "nsNetUtil.h"
45 #include "nsDebug.h"
46 #include "nsAutoPtr.h"
47 #include "nsThreadUtils.h"
48 #include "nsIServiceManager.h"
49 #include "nsIJSContextStack.h"
50 #include "nsIScriptSecurityManager.h"
51 #include "nsICryptoHash.h"
54 // nsXPITriggerItem
57 nsXPITriggerItem::nsXPITriggerItem( const PRUnichar* aName,
58 const PRUnichar* aURL,
59 const PRUnichar* aIconURL,
60 const char* aHash,
61 PRInt32 aFlags)
62 : mName(aName), mURL(aURL), mIconURL(aIconURL), mHashFound(PR_FALSE), mFlags(aFlags)
64 MOZ_COUNT_CTOR(nsXPITriggerItem);
66 // check for arguments
67 PRInt32 qmark = mURL.FindChar('?');
68 if ( qmark != kNotFound )
70 mArguments = Substring( mURL, qmark+1, mURL.Length() );
73 // construct name if not passed in
74 if ( mName.IsEmpty() )
76 // Use the filename as the display name by starting after the last
77 // slash in the URL, looking backwards from the arguments delimiter if
78 // we found one. By good fortune using kNotFound as the offset for
79 // RFindChar() starts at the end, so we can use qmark in all cases.
81 PRInt32 namestart = mURL.RFindChar( '/', qmark );
83 // the real start is after the slash (or 0 if not found)
84 namestart = ( namestart==kNotFound ) ? 0 : namestart + 1;
86 PRInt32 length;
87 if (qmark == kNotFound)
88 length = mURL.Length(); // no '?', slurp up rest of URL
89 else
90 length = (qmark - namestart); // filename stops at the '?'
92 mName = Substring( mURL, namestart, length );
95 // parse optional hash into its parts
96 if (aHash)
98 mHashFound = PR_TRUE;
100 char * colon = PL_strchr(aHash, ':');
101 if (colon)
103 mHasher = do_CreateInstance("@mozilla.org/security/hash;1");
104 if (!mHasher) return;
106 *colon = '\0'; // null the colon so that aHash is just the type.
107 nsresult rv = mHasher->InitWithString(nsDependentCString(aHash));
108 *colon = ':'; // restore the colon
110 if (NS_SUCCEEDED(rv))
111 mHash = colon+1;
116 nsXPITriggerItem::~nsXPITriggerItem()
118 MOZ_COUNT_DTOR(nsXPITriggerItem);
121 PRBool nsXPITriggerItem::IsRelativeURL()
123 PRInt32 cpos = mURL.FindChar(':');
124 if (cpos == kNotFound)
125 return PR_TRUE;
127 PRInt32 spos = mURL.FindChar('/');
128 return (cpos > spos);
131 const PRUnichar*
132 nsXPITriggerItem::GetSafeURLString()
134 // create the safe url string the first time
135 if (mSafeURL.IsEmpty() && !mURL.IsEmpty())
137 nsCOMPtr<nsIURI> uri;
138 NS_NewURI(getter_AddRefs(uri), mURL);
139 if (uri)
141 nsCAutoString spec;
142 uri->SetUserPass(EmptyCString());
143 uri->GetSpec(spec);
144 mSafeURL = NS_ConvertUTF8toUTF16(spec);
148 return mSafeURL.get();
151 void
152 nsXPITriggerItem::SetPrincipal(nsIPrincipal* aPrincipal)
154 mPrincipal = aPrincipal;
156 // aPrincipal can be null for various failure cases.
157 // see bug 213894 for an example.
158 // nsXPInstallManager::OnCertAvailable can be called with a null principal
159 // and it can also force a null principal.
160 if (!aPrincipal)
161 return;
163 PRBool hasCert;
164 aPrincipal->GetHasCertificate(&hasCert);
165 if (hasCert) {
166 nsCAutoString prettyName;
167 // XXXbz should this really be using the prettyName? Perhaps
168 // it wants to get the subjectName or nsIX509Cert and display
169 // it sanely?
170 aPrincipal->GetPrettyName(prettyName);
171 CopyUTF8toUTF16(prettyName, mCertName);
176 // nsXPITriggerInfo
179 nsXPITriggerInfo::nsXPITriggerInfo()
180 : mCx(0), mCbval(JSVAL_NULL)
182 MOZ_COUNT_CTOR(nsXPITriggerInfo);
185 nsXPITriggerInfo::~nsXPITriggerInfo()
187 nsXPITriggerItem* item;
189 for(PRUint32 i=0; i < Size(); i++)
191 item = Get(i);
192 if (item)
193 delete item;
195 mItems.Clear();
197 if ( mCx && !JSVAL_IS_NULL(mCbval) ) {
198 JS_BeginRequest(mCx);
199 JS_RemoveRoot( mCx, &mCbval );
200 JS_EndRequest(mCx);
203 MOZ_COUNT_DTOR(nsXPITriggerInfo);
206 void nsXPITriggerInfo::SaveCallback( JSContext *aCx, jsval aVal )
208 NS_ASSERTION( mCx == 0, "callback set twice, memory leak" );
209 mCx = aCx;
210 JSObject *obj = JS_GetGlobalObject( mCx );
212 JSClass* clazz;
214 clazz = ::JS_GET_CLASS(aCx, obj);
216 if (clazz &&
217 (clazz->flags & JSCLASS_HAS_PRIVATE) &&
218 (clazz->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS)) {
219 mGlobalWrapper =
220 do_QueryInterface((nsISupports*)::JS_GetPrivate(aCx, obj));
223 mCbval = aVal;
224 mThread = do_GetCurrentThread();
226 if ( !JSVAL_IS_NULL(mCbval) ) {
227 JS_BeginRequest(mCx);
228 JS_AddRoot( mCx, &mCbval );
229 JS_EndRequest(mCx);
233 XPITriggerEvent::~XPITriggerEvent()
235 JS_BeginRequest(cx);
236 JS_RemoveRoot(cx, &cbval);
237 JS_EndRequest(cx);
240 NS_IMETHODIMP
241 XPITriggerEvent::Run()
243 jsval ret;
244 void* mark;
245 jsval* args;
247 JS_BeginRequest(cx);
248 args = JS_PushArguments(cx, &mark, "Wi",
249 URL.get(),
250 status);
251 if ( args )
253 // This code is all in a JS request, and here we're about to
254 // push the context onto the context stack and also push
255 // arguments. Be very very sure that no early returns creep in
256 // here w/o doing the proper cleanup!
258 const char *errorStr = nsnull;
260 nsCOMPtr<nsIJSContextStack> stack =
261 do_GetService("@mozilla.org/js/xpc/ContextStack;1");
262 if (stack)
263 stack->Push(cx);
265 nsCOMPtr<nsIScriptSecurityManager> secman =
266 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
268 if (!secman)
270 errorStr = "Could not get script security manager service";
273 nsCOMPtr<nsIPrincipal> principal;
274 if (!errorStr)
276 secman->GetSubjectPrincipal(getter_AddRefs(principal));
277 if (!principal)
279 errorStr = "Could not get principal from script security manager";
283 if (!errorStr)
285 PRBool equals = PR_FALSE;
286 principal->Equals(princ, &equals);
288 if (!equals)
290 errorStr = "Principal of callback context is different than InstallTriggers";
294 if (errorStr)
296 JS_ReportError(cx, errorStr);
298 else
300 JS_CallFunctionValue(cx,
301 JSVAL_TO_OBJECT(global),
302 cbval,
304 args,
305 &ret);
308 if (stack)
309 stack->Pop(nsnull);
311 JS_PopArguments(cx, mark);
313 JS_EndRequest(cx);
315 return 0;
319 void nsXPITriggerInfo::SendStatus(const PRUnichar* URL, PRInt32 status)
321 nsresult rv;
323 if ( mCx && mGlobalWrapper && !JSVAL_IS_NULL(mCbval) )
325 // create event and post it
326 nsRefPtr<XPITriggerEvent> event = new XPITriggerEvent();
327 if (event)
329 event->URL = URL;
330 event->status = status;
331 event->cx = mCx;
332 event->princ = mPrincipal;
334 JSObject *obj = nsnull;
336 mGlobalWrapper->GetJSObject(&obj);
338 event->global = OBJECT_TO_JSVAL(obj);
340 event->cbval = mCbval;
341 JS_BeginRequest(event->cx);
342 JS_AddNamedRoot(event->cx, &event->cbval,
343 "XPITriggerEvent::cbval" );
344 JS_EndRequest(event->cx);
346 // Hold a strong reference to keep the underlying
347 // JSContext from dying before we handle this event.
348 event->ref = mGlobalWrapper;
350 rv = mThread->Dispatch(event, NS_DISPATCH_NORMAL);
352 else
353 rv = NS_ERROR_OUT_OF_MEMORY;
355 if ( NS_FAILED( rv ) )
357 // couldn't get event queue -- maybe window is gone or
358 // some similarly catastrophic occurrance
359 NS_WARNING("failed to dispatch XPITriggerEvent");