Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / netwerk / base / src / nsAsyncStreamCopier.cpp
blob5430d15187bfe7c3c981f1a3b88f03d025f8dd60
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is Mozilla.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 2002
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
22 * Darin Fisher <darin@netscape.com>
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 #include "nsAsyncStreamCopier.h"
39 #include "nsIEventTarget.h"
40 #include "nsStreamUtils.h"
41 #include "nsNetSegmentUtils.h"
42 #include "nsNetUtil.h"
43 #include "nsAutoLock.h"
44 #include "prlog.h"
46 #if defined(PR_LOGGING)
48 // NSPR_LOG_MODULES=nsStreamCopier:5
50 static PRLogModuleInfo *gStreamCopierLog = nsnull;
51 #endif
52 #define LOG(args) PR_LOG(gStreamCopierLog, PR_LOG_DEBUG, args)
54 //-----------------------------------------------------------------------------
56 nsAsyncStreamCopier::nsAsyncStreamCopier()
57 : mLock(nsnull)
58 , mMode(NS_ASYNCCOPY_VIA_READSEGMENTS)
59 , mChunkSize(NET_DEFAULT_SEGMENT_SIZE)
60 , mStatus(NS_OK)
61 , mIsPending(PR_FALSE)
63 #if defined(PR_LOGGING)
64 if (!gStreamCopierLog)
65 gStreamCopierLog = PR_NewLogModule("nsStreamCopier");
66 #endif
67 LOG(("Creating nsAsyncStreamCopier @%x\n", this));
70 nsAsyncStreamCopier::~nsAsyncStreamCopier()
72 LOG(("Destroying nsAsyncStreamCopier @%x\n", this));
73 if (mLock)
74 PR_DestroyLock(mLock);
77 PRBool
78 nsAsyncStreamCopier::IsComplete(nsresult *status)
80 nsAutoLock lock(mLock);
81 if (status)
82 *status = mStatus;
83 return !mIsPending;
86 void
87 nsAsyncStreamCopier::Complete(nsresult status)
89 LOG(("nsAsyncStreamCopier::Complete [this=%x status=%x]\n", this, status));
91 nsCOMPtr<nsIRequestObserver> observer;
92 nsCOMPtr<nsISupports> ctx;
94 nsAutoLock lock(mLock);
95 if (mIsPending) {
96 mIsPending = PR_FALSE;
97 mStatus = status;
99 // setup OnStopRequest callback and release references...
100 observer = mObserver;
101 ctx = mObserverContext;
102 mObserver = nsnull;
103 mObserverContext = nsnull;
107 if (observer) {
108 LOG((" calling OnStopRequest [status=%x]\n", status));
109 observer->OnStopRequest(this, ctx, status);
113 void
114 nsAsyncStreamCopier::OnAsyncCopyComplete(void *closure, nsresult status)
116 nsAsyncStreamCopier *self = (nsAsyncStreamCopier *) closure;
117 self->Complete(status);
118 NS_RELEASE(self); // addref'd in AsyncCopy
121 //-----------------------------------------------------------------------------
122 // nsISupports
124 NS_IMPL_THREADSAFE_ISUPPORTS2(nsAsyncStreamCopier,
125 nsIRequest,
126 nsIAsyncStreamCopier)
128 //-----------------------------------------------------------------------------
129 // nsIRequest
131 NS_IMETHODIMP
132 nsAsyncStreamCopier::GetName(nsACString &name)
134 name.Truncate();
135 return NS_OK;
138 NS_IMETHODIMP
139 nsAsyncStreamCopier::IsPending(PRBool *result)
141 *result = !IsComplete();
142 return NS_OK;
145 NS_IMETHODIMP
146 nsAsyncStreamCopier::GetStatus(nsresult *status)
148 IsComplete(status);
149 return NS_OK;
152 NS_IMETHODIMP
153 nsAsyncStreamCopier::Cancel(nsresult status)
155 if (IsComplete())
156 return NS_OK;
158 if (NS_SUCCEEDED(status)) {
159 NS_WARNING("cancel with non-failure status code");
160 status = NS_BASE_STREAM_CLOSED;
163 nsCOMPtr<nsIAsyncInputStream> asyncSource = do_QueryInterface(mSource);
164 if (asyncSource)
165 asyncSource->CloseWithStatus(status);
166 else
167 mSource->Close();
169 nsCOMPtr<nsIAsyncOutputStream> asyncSink = do_QueryInterface(mSink);
170 if (asyncSink)
171 asyncSink->CloseWithStatus(status);
172 else
173 mSink->Close();
175 return NS_OK;
178 NS_IMETHODIMP
179 nsAsyncStreamCopier::Suspend()
181 NS_NOTREACHED("nsAsyncStreamCopier::Suspend");
182 return NS_ERROR_NOT_IMPLEMENTED;
185 NS_IMETHODIMP
186 nsAsyncStreamCopier::Resume()
188 NS_NOTREACHED("nsAsyncStreamCopier::Resume");
189 return NS_ERROR_NOT_IMPLEMENTED;
192 NS_IMETHODIMP
193 nsAsyncStreamCopier::GetLoadFlags(nsLoadFlags *aLoadFlags)
195 *aLoadFlags = LOAD_NORMAL;
196 return NS_OK;
199 NS_IMETHODIMP
200 nsAsyncStreamCopier::SetLoadFlags(nsLoadFlags aLoadFlags)
202 return NS_OK;
205 NS_IMETHODIMP
206 nsAsyncStreamCopier::GetLoadGroup(nsILoadGroup **aLoadGroup)
208 *aLoadGroup = nsnull;
209 return NS_OK;
212 NS_IMETHODIMP
213 nsAsyncStreamCopier::SetLoadGroup(nsILoadGroup *aLoadGroup)
215 return NS_OK;
218 //-----------------------------------------------------------------------------
219 // nsIAsyncStreamCopier
221 NS_IMETHODIMP
222 nsAsyncStreamCopier::Init(nsIInputStream *source,
223 nsIOutputStream *sink,
224 nsIEventTarget *target,
225 PRBool sourceBuffered,
226 PRBool sinkBuffered,
227 PRUint32 chunkSize)
229 NS_ASSERTION(sourceBuffered || sinkBuffered, "at least one stream must be buffered");
231 NS_ASSERTION(!mLock, "already initialized");
232 mLock = PR_NewLock();
233 if (!mLock)
234 return NS_ERROR_OUT_OF_MEMORY;
236 if (chunkSize == 0)
237 chunkSize = NET_DEFAULT_SEGMENT_SIZE;
238 mChunkSize = chunkSize;
240 mSource = source;
241 mSink = sink;
243 mMode = sourceBuffered ? NS_ASYNCCOPY_VIA_READSEGMENTS
244 : NS_ASYNCCOPY_VIA_WRITESEGMENTS;
245 if (target)
246 mTarget = target;
247 else {
248 nsresult rv;
249 mTarget = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
250 if (NS_FAILED(rv)) return rv;
252 return NS_OK;
255 NS_IMETHODIMP
256 nsAsyncStreamCopier::AsyncCopy(nsIRequestObserver *observer, nsISupports *ctx)
258 LOG(("nsAsyncStreamCopier::AsyncCopy [this=%x observer=%x]\n", this, observer));
260 NS_ASSERTION(mSource && mSink, "not initialized");
261 nsresult rv;
263 if (observer) {
264 // build proxy for observer events
265 rv = NS_NewRequestObserverProxy(getter_AddRefs(mObserver), observer);
266 if (NS_FAILED(rv)) return rv;
269 // from this point forward, AsyncCopy is going to return NS_OK. any errors
270 // will be reported via OnStopRequest.
271 mIsPending = PR_TRUE;
273 mObserverContext = ctx;
274 if (mObserver) {
275 rv = mObserver->OnStartRequest(this, mObserverContext);
276 if (NS_FAILED(rv))
277 Cancel(rv);
280 // we want to receive progress notifications; release happens in
281 // OnAsyncCopyComplete.
282 NS_ADDREF_THIS();
283 rv = NS_AsyncCopy(mSource, mSink, mTarget, mMode, mChunkSize,
284 OnAsyncCopyComplete, this);
285 if (NS_FAILED(rv)) {
286 NS_RELEASE_THIS();
287 Cancel(rv);
290 return NS_OK;