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
4 : *
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/
9 : *
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.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 2001
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Darin Fisher <darin@netscape.com> (original author)
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * 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 : #include "nscore.h"
40 : #include "nsRequestObserverProxy.h"
41 : #include "nsIRequest.h"
42 : #include "nsIServiceManager.h"
43 : #include "nsProxyRelease.h"
44 : #include "nsAutoPtr.h"
45 : #include "nsString.h"
46 : #include "prlog.h"
47 :
48 : #if defined(PR_LOGGING)
49 : static PRLogModuleInfo *gRequestObserverProxyLog;
50 : #endif
51 :
52 : #define LOG(args) PR_LOG(gRequestObserverProxyLog, PR_LOG_DEBUG, args)
53 :
54 : //-----------------------------------------------------------------------------
55 : // nsARequestObserverEvent internal class...
56 : //-----------------------------------------------------------------------------
57 :
58 795 : nsARequestObserverEvent::nsARequestObserverEvent(nsIRequest *request,
59 : nsISupports *context)
60 : : mRequest(request)
61 795 : , mContext(context)
62 : {
63 795 : NS_PRECONDITION(mRequest, "null pointer");
64 795 : }
65 :
66 : //-----------------------------------------------------------------------------
67 : // nsOnStartRequestEvent internal class...
68 : //-----------------------------------------------------------------------------
69 :
70 : class nsOnStartRequestEvent : public nsARequestObserverEvent
71 : {
72 : nsRefPtr<nsRequestObserverProxy> mProxy;
73 : public:
74 399 : nsOnStartRequestEvent(nsRequestObserverProxy *proxy,
75 : nsIRequest *request,
76 : nsISupports *context)
77 : : nsARequestObserverEvent(request, context)
78 399 : , mProxy(proxy)
79 : {
80 399 : NS_PRECONDITION(mProxy, "null pointer");
81 399 : }
82 :
83 1596 : virtual ~nsOnStartRequestEvent() {}
84 :
85 399 : NS_IMETHOD Run()
86 : {
87 399 : LOG(("nsOnStartRequestEvent::HandleEvent [req=%x]\n", mRequest.get()));
88 :
89 399 : if (!mProxy->mObserver) {
90 0 : NS_NOTREACHED("already handled onStopRequest event (observer is null)");
91 0 : return NS_OK;
92 : }
93 :
94 399 : LOG(("handle startevent=%p\n", this));
95 399 : nsresult rv = mProxy->mObserver->OnStartRequest(mRequest, mContext);
96 399 : if (NS_FAILED(rv)) {
97 0 : LOG(("OnStartRequest failed [rv=%x] canceling request!\n", rv));
98 0 : rv = mRequest->Cancel(rv);
99 0 : NS_ASSERTION(NS_SUCCEEDED(rv), "Cancel failed for request!");
100 : }
101 :
102 399 : return NS_OK;
103 : }
104 : };
105 :
106 : //-----------------------------------------------------------------------------
107 : // nsOnStopRequestEvent internal class...
108 : //-----------------------------------------------------------------------------
109 :
110 : class nsOnStopRequestEvent : public nsARequestObserverEvent
111 : {
112 : nsRefPtr<nsRequestObserverProxy> mProxy;
113 : public:
114 396 : nsOnStopRequestEvent(nsRequestObserverProxy *proxy,
115 : nsIRequest *request, nsISupports *context)
116 : : nsARequestObserverEvent(request, context)
117 396 : , mProxy(proxy)
118 : {
119 396 : NS_PRECONDITION(mProxy, "null pointer");
120 396 : }
121 :
122 1584 : virtual ~nsOnStopRequestEvent() {}
123 :
124 396 : NS_IMETHOD Run()
125 : {
126 396 : nsresult rv, status = NS_OK;
127 :
128 396 : LOG(("nsOnStopRequestEvent::HandleEvent [req=%x]\n", mRequest.get()));
129 :
130 792 : nsCOMPtr<nsIRequestObserver> observer = mProxy->mObserver;
131 396 : if (!observer) {
132 0 : NS_NOTREACHED("already handled onStopRequest event (observer is null)");
133 0 : return NS_OK;
134 : }
135 : // Do not allow any more events to be handled after OnStopRequest
136 396 : mProxy->mObserver = 0;
137 :
138 396 : rv = mRequest->GetStatus(&status);
139 396 : NS_ASSERTION(NS_SUCCEEDED(rv), "GetStatus failed for request!");
140 :
141 396 : LOG(("handle stopevent=%p\n", this));
142 396 : (void) observer->OnStopRequest(mRequest, mContext, status);
143 :
144 396 : return NS_OK;
145 : }
146 : };
147 :
148 : //-----------------------------------------------------------------------------
149 : // nsRequestObserverProxy <public>
150 : //-----------------------------------------------------------------------------
151 :
152 1197 : nsRequestObserverProxy::~nsRequestObserverProxy()
153 : {
154 399 : if (mObserver) {
155 : // order is crucial here... we must be careful to clear mObserver
156 : // before posting the proxy release event. otherwise, we'd risk
157 : // releasing the object on this thread.
158 3 : nsIRequestObserver *obs = nsnull;
159 3 : mObserver.swap(obs);
160 3 : NS_ProxyRelease(mTarget, obs);
161 : }
162 1596 : }
163 :
164 : //-----------------------------------------------------------------------------
165 : // nsRequestObserverProxy::nsISupports implementation...
166 : //-----------------------------------------------------------------------------
167 :
168 7569 : NS_IMPL_THREADSAFE_ISUPPORTS2(nsRequestObserverProxy,
169 : nsIRequestObserver,
170 : nsIRequestObserverProxy)
171 :
172 : //-----------------------------------------------------------------------------
173 : // nsRequestObserverProxy::nsIRequestObserver implementation...
174 : //-----------------------------------------------------------------------------
175 :
176 : NS_IMETHODIMP
177 399 : nsRequestObserverProxy::OnStartRequest(nsIRequest *request,
178 : nsISupports *context)
179 : {
180 399 : LOG(("nsRequestObserverProxy::OnStartRequest [this=%x req=%x]\n", this, request));
181 :
182 : nsOnStartRequestEvent *ev =
183 399 : new nsOnStartRequestEvent(this, request, context);
184 399 : if (!ev)
185 0 : return NS_ERROR_OUT_OF_MEMORY;
186 :
187 399 : LOG(("post startevent=%p queue=%p\n", ev, mTarget.get()));
188 399 : nsresult rv = FireEvent(ev);
189 399 : if (NS_FAILED(rv))
190 0 : delete ev;
191 399 : return rv;
192 : }
193 :
194 : NS_IMETHODIMP
195 396 : nsRequestObserverProxy::OnStopRequest(nsIRequest *request,
196 : nsISupports *context,
197 : nsresult status)
198 : {
199 396 : LOG(("nsRequestObserverProxy: OnStopRequest [this=%x req=%x status=%x]\n",
200 : this, request, status));
201 :
202 : // The status argument is ignored because, by the time the OnStopRequestEvent
203 : // is actually processed, the status of the request may have changed :-(
204 : // To make sure that an accurate status code is always used, GetStatus() is
205 : // called when the OnStopRequestEvent is actually processed (see above).
206 :
207 : nsOnStopRequestEvent *ev =
208 396 : new nsOnStopRequestEvent(this, request, context);
209 396 : if (!ev)
210 0 : return NS_ERROR_OUT_OF_MEMORY;
211 :
212 396 : LOG(("post stopevent=%p queue=%p\n", ev, mTarget.get()));
213 396 : nsresult rv = FireEvent(ev);
214 396 : if (NS_FAILED(rv))
215 0 : delete ev;
216 396 : return rv;
217 : }
218 :
219 : //-----------------------------------------------------------------------------
220 : // nsRequestObserverProxy::nsIRequestObserverProxy implementation...
221 : //-----------------------------------------------------------------------------
222 :
223 : NS_IMETHODIMP
224 399 : nsRequestObserverProxy::Init(nsIRequestObserver *observer,
225 : nsIEventTarget *target)
226 : {
227 399 : NS_ENSURE_ARG_POINTER(observer);
228 :
229 : #if defined(PR_LOGGING)
230 399 : if (!gRequestObserverProxyLog)
231 25 : gRequestObserverProxyLog = PR_NewLogModule("nsRequestObserverProxy");
232 : #endif
233 :
234 399 : mObserver = observer;
235 :
236 399 : SetTarget(target ? target : NS_GetCurrentThread());
237 399 : NS_ENSURE_STATE(mTarget);
238 :
239 399 : return NS_OK;
240 : }
241 :
242 : //-----------------------------------------------------------------------------
243 : // nsRequestObserverProxy implementation...
244 : //-----------------------------------------------------------------------------
245 :
246 : nsresult
247 795 : nsRequestObserverProxy::FireEvent(nsARequestObserverEvent *event)
248 : {
249 795 : NS_ENSURE_TRUE(mTarget, NS_ERROR_NOT_INITIALIZED);
250 795 : return mTarget->Dispatch(event, NS_DISPATCH_NORMAL);
251 : }
|