Back to index

lightning-sunbird  0.9+nobinonly
nsAsyncStreamCopier.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is Mozilla.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 2002
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Darin Fisher <darin@netscape.com>
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "nsAsyncStreamCopier.h"
00039 #include "nsStreamUtils.h"
00040 #include "nsNetSegmentUtils.h"
00041 #include "nsNetUtil.h"
00042 #include "nsAutoLock.h"
00043 #include "prlog.h"
00044 
00045 #if defined(PR_LOGGING)
00046 //
00047 // NSPR_LOG_MODULES=nsStreamCopier:5
00048 //
00049 static PRLogModuleInfo *gStreamCopierLog = nsnull;
00050 #endif
00051 #define LOG(args) PR_LOG(gStreamCopierLog, PR_LOG_DEBUG, args)
00052 
00053 //-----------------------------------------------------------------------------
00054 
00055 nsAsyncStreamCopier::nsAsyncStreamCopier()
00056     : mLock(nsnull)
00057     , mMode(NS_ASYNCCOPY_VIA_READSEGMENTS)
00058     , mChunkSize(NET_DEFAULT_SEGMENT_SIZE)
00059     , mStatus(NS_OK)
00060     , mIsPending(PR_FALSE)
00061 {
00062 #if defined(PR_LOGGING)
00063     if (!gStreamCopierLog)
00064         gStreamCopierLog = PR_NewLogModule("nsStreamCopier");
00065 #endif
00066     LOG(("Creating nsAsyncStreamCopier @%x\n", this));
00067 }
00068 
00069 nsAsyncStreamCopier::~nsAsyncStreamCopier()
00070 {
00071     LOG(("Destroying nsAsyncStreamCopier @%x\n", this));
00072     if (mLock)
00073         PR_DestroyLock(mLock);
00074 }
00075 
00076 PRBool
00077 nsAsyncStreamCopier::IsComplete(nsresult *status)
00078 {
00079     nsAutoLock lock(mLock);
00080     if (status)
00081         *status = mStatus;
00082     return !mIsPending;
00083 }
00084 
00085 void
00086 nsAsyncStreamCopier::Complete(nsresult status)
00087 {
00088     LOG(("nsAsyncStreamCopier::Complete [this=%x status=%x]\n", this, status));
00089 
00090     nsCOMPtr<nsIRequestObserver> observer;
00091     nsCOMPtr<nsISupports> ctx;
00092     {
00093         nsAutoLock lock(mLock);
00094         if (mIsPending) {
00095             mIsPending = PR_FALSE;
00096             mStatus = status;
00097 
00098             // setup OnStopRequest callback and release references...
00099             observer = mObserver;
00100             ctx = mObserverContext;
00101             mObserver = nsnull;
00102             mObserverContext = nsnull;
00103         }
00104     }
00105 
00106     if (observer) {
00107         LOG(("  calling OnStopRequest [status=%x]\n", status));
00108         observer->OnStopRequest(this, ctx, status);
00109     }
00110 }
00111 
00112 void
00113 nsAsyncStreamCopier::OnAsyncCopyComplete(void *closure, nsresult status)
00114 {
00115     nsAsyncStreamCopier *self = (nsAsyncStreamCopier *) closure;
00116     self->Complete(status);
00117     NS_RELEASE(self); // addref'd in AsyncCopy
00118 }
00119 
00120 //-----------------------------------------------------------------------------
00121 // nsISupports
00122 
00123 NS_IMPL_THREADSAFE_ISUPPORTS2(nsAsyncStreamCopier,
00124                               nsIRequest,
00125                               nsIAsyncStreamCopier)
00126 
00127 //-----------------------------------------------------------------------------
00128 // nsIRequest
00129 
00130 NS_IMETHODIMP
00131 nsAsyncStreamCopier::GetName(nsACString &name)
00132 {
00133     name.Truncate();
00134     return NS_OK;
00135 }
00136 
00137 NS_IMETHODIMP
00138 nsAsyncStreamCopier::IsPending(PRBool *result)
00139 {
00140     *result = !IsComplete();
00141     return NS_OK;
00142 }
00143 
00144 NS_IMETHODIMP
00145 nsAsyncStreamCopier::GetStatus(nsresult *status)
00146 {
00147     IsComplete(status);
00148     return NS_OK;
00149 }
00150 
00151 NS_IMETHODIMP
00152 nsAsyncStreamCopier::Cancel(nsresult status)
00153 {
00154     if (IsComplete())
00155         return NS_OK;
00156 
00157     if (NS_SUCCEEDED(status)) {
00158         NS_WARNING("cancel with non-failure status code");
00159         status = NS_BASE_STREAM_CLOSED;
00160     }
00161 
00162     nsCOMPtr<nsIAsyncInputStream> asyncSource = do_QueryInterface(mSource);
00163     if (asyncSource)
00164         asyncSource->CloseWithStatus(status);
00165     else
00166         mSource->Close();
00167 
00168     nsCOMPtr<nsIAsyncOutputStream> asyncSink = do_QueryInterface(mSink);
00169     if (asyncSink)
00170         asyncSink->CloseWithStatus(status);
00171     else
00172         mSink->Close();
00173 
00174     return NS_OK;
00175 }
00176 
00177 NS_IMETHODIMP
00178 nsAsyncStreamCopier::Suspend()
00179 {
00180     NS_NOTREACHED("nsAsyncStreamCopier::Suspend");
00181     return NS_ERROR_NOT_IMPLEMENTED;
00182 }
00183 
00184 NS_IMETHODIMP
00185 nsAsyncStreamCopier::Resume()
00186 {
00187     NS_NOTREACHED("nsAsyncStreamCopier::Resume");
00188     return NS_ERROR_NOT_IMPLEMENTED;
00189 }
00190 
00191 NS_IMETHODIMP
00192 nsAsyncStreamCopier::GetLoadFlags(nsLoadFlags *aLoadFlags)
00193 {
00194     *aLoadFlags = LOAD_NORMAL;
00195     return NS_OK;
00196 }
00197 
00198 NS_IMETHODIMP
00199 nsAsyncStreamCopier::SetLoadFlags(nsLoadFlags aLoadFlags)
00200 {
00201     return NS_OK;
00202 }
00203 
00204 NS_IMETHODIMP
00205 nsAsyncStreamCopier::GetLoadGroup(nsILoadGroup **aLoadGroup)
00206 {
00207     *aLoadGroup = nsnull;
00208     return NS_OK;
00209 }
00210 
00211 NS_IMETHODIMP
00212 nsAsyncStreamCopier::SetLoadGroup(nsILoadGroup *aLoadGroup)
00213 {
00214     return NS_OK;
00215 }
00216 
00217 //-----------------------------------------------------------------------------
00218 // nsIAsyncStreamCopier
00219 
00220 NS_IMETHODIMP
00221 nsAsyncStreamCopier::Init(nsIInputStream *source,
00222                           nsIOutputStream *sink,
00223                           nsIEventTarget *target,
00224                           PRBool sourceBuffered,
00225                           PRBool sinkBuffered,
00226                           PRUint32 chunkSize)
00227 {
00228     NS_ASSERTION(sourceBuffered || sinkBuffered, "at least one stream must be buffered");
00229 
00230     NS_ASSERTION(!mLock, "already initialized");
00231     mLock = PR_NewLock();
00232     if (!mLock)
00233         return NS_ERROR_OUT_OF_MEMORY;
00234 
00235     if (chunkSize == 0)
00236         chunkSize = NET_DEFAULT_SEGMENT_SIZE;
00237     mChunkSize = chunkSize;
00238 
00239     mSource = source;
00240     mSink = sink;
00241 
00242     mMode = sourceBuffered ? NS_ASYNCCOPY_VIA_READSEGMENTS
00243                            : NS_ASYNCCOPY_VIA_WRITESEGMENTS;
00244     if (target)
00245         mTarget = target;
00246     else {
00247         nsresult rv;
00248         mTarget = do_GetService(NS_IOTHREADPOOL_CONTRACTID, &rv);
00249         if (NS_FAILED(rv)) return rv;
00250     }
00251     return NS_OK;
00252 }
00253 
00254 NS_IMETHODIMP
00255 nsAsyncStreamCopier::AsyncCopy(nsIRequestObserver *observer, nsISupports *ctx)
00256 {
00257     LOG(("nsAsyncStreamCopier::AsyncCopy [this=%x observer=%x]\n", this, observer));
00258 
00259     NS_ASSERTION(mSource && mSink, "not initialized");
00260     nsresult rv;
00261 
00262     if (observer) {
00263         // build proxy for observer events
00264         rv = NS_NewRequestObserverProxy(getter_AddRefs(mObserver), observer);
00265         if (NS_FAILED(rv)) return rv;
00266     }
00267 
00268     // from this point forward, AsyncCopy is going to return NS_OK.  any errors
00269     // will be reported via OnStopRequest.
00270     mIsPending = PR_TRUE;
00271 
00272     mObserverContext = ctx;
00273     if (mObserver) {
00274         rv = mObserver->OnStartRequest(this, mObserverContext);
00275         if (NS_FAILED(rv))
00276             Cancel(rv);
00277     }
00278     
00279     // we want to receive progress notifications; release happens in
00280     // OnAsyncCopyComplete.
00281     NS_ADDREF_THIS();
00282     rv = NS_AsyncCopy(mSource, mSink, mTarget, mMode, mChunkSize,
00283                       OnAsyncCopyComplete, this);
00284     if (NS_FAILED(rv)) {
00285         NS_RELEASE_THIS();
00286         Cancel(rv);
00287     }
00288 
00289     return NS_OK;
00290 }