Back to index

lightning-sunbird  0.9+nobinonly
nsAsyncStreamListener.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
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 "nsAsyncStreamListener.h"
00039 #include "nsIInputStream.h"
00040 #include "nsString.h"
00041 #include "nsCRT.h"
00042 #include "nsIEventQueueService.h"
00043 #include "nsIIOService.h"
00044 #include "nsIServiceManager.h"
00045 #include "nsIChannel.h"
00046 #include "prlog.h"
00047 
00048 static NS_DEFINE_CID(kEventQueueService, NS_EVENTQUEUESERVICE_CID);
00049 
00050 #if defined(PR_LOGGING)
00051 PRLogModuleInfo* gStreamEventLog = 0;
00052 #endif
00053 
00054 // prevent name conflicts
00055 #define nsStreamListenerEvent  nsStreamListenerEvent0
00056 #define nsOnStartRequestEvent  nsOnStartRequestEvent0
00057 #define nsOnStopRequestEvent   nsOnStopRequestEvent0
00058 #define nsOnDataAvailableEvent nsOnDataAvailableEvent0
00059 
00061 
00062 class nsStreamListenerEvent
00063 {
00064 public:
00065     nsStreamListenerEvent(nsAsyncStreamObserver* listener,
00066                           nsIRequest* request, nsISupports* context);
00067     virtual ~nsStreamListenerEvent();
00068 
00069     nsresult Fire(nsIEventQueue* aEventQ);
00070 
00071     NS_IMETHOD HandleEvent() = 0;
00072 
00073 protected:
00074     static void PR_CALLBACK HandlePLEvent(PLEvent* aEvent);
00075     static void PR_CALLBACK DestroyPLEvent(PLEvent* aEvent);
00076 
00077     nsAsyncStreamObserver*      mListener;
00078     nsIRequest*                 mRequest;
00079     nsISupports*                mContext;
00080     PLEvent                     mEvent;
00081 };
00082 
00083 #define GET_STREAM_LISTENER_EVENT(_this) \
00084     ((nsStreamListenerEvent*)((char*)(_this) - offsetof(nsStreamListenerEvent, mEvent)))
00085 
00087 
00088 nsStreamListenerEvent::nsStreamListenerEvent(nsAsyncStreamObserver* listener,
00089                                              nsIRequest* request, nsISupports* context)
00090     : mListener(listener), mRequest(request), mContext(context)
00091 {
00092     MOZ_COUNT_CTOR(nsStreamListenerEvent);
00093 
00094     NS_IF_ADDREF(mListener);
00095     NS_IF_ADDREF(mRequest);
00096     NS_IF_ADDREF(mContext);
00097 }
00098 
00099 nsStreamListenerEvent::~nsStreamListenerEvent()
00100 {
00101     MOZ_COUNT_DTOR(nsStreamListenerEvent);
00102 
00103     NS_IF_RELEASE(mListener);
00104     NS_IF_RELEASE(mRequest);
00105     NS_IF_RELEASE(mContext);
00106 }
00107 
00108 void PR_CALLBACK nsStreamListenerEvent::HandlePLEvent(PLEvent* aEvent)
00109 {
00110     nsStreamListenerEvent* ev = GET_STREAM_LISTENER_EVENT(aEvent);
00111     NS_ASSERTION(nsnull != ev,"null event.");
00112 
00113     nsresult rv = ev->HandleEvent();
00114     //
00115     // If the consumer fails, then cancel the transport.  This is necessary
00116     // in case where the socket transport is blocked waiting for room in the
00117     // pipe, but the consumer fails without consuming all the data.
00118     //
00119     // Unless the transport is cancelled, it will block forever, waiting for
00120     // the pipe to empty...
00121     //
00122     if (NS_FAILED(rv)) {
00123         nsresult cancelRv = ev->mRequest->Cancel(rv);
00124         NS_ASSERTION(NS_SUCCEEDED(cancelRv), "Cancel failed");
00125     }
00126 }
00127 
00128 void PR_CALLBACK nsStreamListenerEvent::DestroyPLEvent(PLEvent* aEvent)
00129 {
00130     nsStreamListenerEvent* ev = GET_STREAM_LISTENER_EVENT(aEvent);
00131     NS_ASSERTION(nsnull != ev, "null event.");
00132     delete ev;
00133 }
00134 
00135 nsresult
00136 nsStreamListenerEvent::Fire(nsIEventQueue* aEventQueue) 
00137 {
00138     NS_PRECONDITION(nsnull != aEventQueue, "nsIEventQueue for thread is null");
00139 
00140     PL_InitEvent(&mEvent,
00141                  nsnull,
00142                  (PLHandleEventProc)  nsStreamListenerEvent::HandlePLEvent,
00143                  (PLDestroyEventProc) nsStreamListenerEvent::DestroyPLEvent);
00144 
00145     return aEventQueue->PostEvent(&mEvent);
00146 }
00147 
00149 
00150 NS_IMPL_THREADSAFE_ISUPPORTS1(nsAsyncStreamObserver,
00151                               nsIRequestObserver)
00152 
00153 NS_IMPL_ADDREF_INHERITED(nsAsyncStreamListener, nsAsyncStreamObserver)
00154 NS_IMPL_RELEASE_INHERITED(nsAsyncStreamListener, nsAsyncStreamObserver)
00155 
00156 NS_IMETHODIMP 
00157 nsAsyncStreamListener::QueryInterface(REFNSIID aIID, void** aInstancePtr)
00158 {
00159   if (!aInstancePtr) return NS_ERROR_NULL_POINTER;
00160   if (aIID.Equals(NS_GET_IID(nsIAsyncStreamListener))) {
00161     *aInstancePtr = NS_STATIC_CAST(nsIAsyncStreamListener*, this);
00162     NS_ADDREF_THIS();
00163     return NS_OK;
00164   }
00165   if (aIID.Equals(NS_GET_IID(nsIStreamListener))) {
00166     *aInstancePtr = NS_STATIC_CAST(nsIStreamListener*, this);
00167     NS_ADDREF_THIS();
00168     return NS_OK;
00169   }
00170   return nsAsyncStreamObserver::QueryInterface(aIID, aInstancePtr);
00171 }
00172 
00173 NS_IMETHODIMP
00174 nsAsyncStreamObserver::Init(nsIRequestObserver* aObserver, nsIEventQueue* aEventQ)
00175 {
00176     nsresult rv = NS_OK;
00177     NS_ASSERTION(aObserver, "null observer");
00178     mReceiver = aObserver;
00179         
00180     nsCOMPtr<nsIEventQueueService> eventQService = 
00181              do_GetService(kEventQueueService, &rv);
00182     if (NS_FAILED(rv)) 
00183     return rv;
00184         
00185     rv = eventQService->ResolveEventQueue(aEventQ, getter_AddRefs(mEventQueue));
00186     return rv;
00187 }
00188 
00190 //
00191 // OnStartRequest...
00192 //
00194 
00195 class nsOnStartRequestEvent : public nsStreamListenerEvent
00196 {
00197 public:
00198     nsOnStartRequestEvent(nsAsyncStreamObserver* listener, 
00199                           nsIRequest* request, nsISupports* context)
00200         : nsStreamListenerEvent(listener, request, context) {}
00201     virtual ~nsOnStartRequestEvent() {}
00202 
00203     NS_IMETHOD HandleEvent();
00204 };
00205 
00206 NS_IMETHODIMP
00207 nsOnStartRequestEvent::HandleEvent()
00208 {
00209 #if defined(PR_LOGGING)
00210   if (!gStreamEventLog)
00211       gStreamEventLog = PR_NewLogModule("netlibStreamEvent");
00212   PR_LOG(gStreamEventLog, PR_LOG_DEBUG,
00213          ("netlibEvent: Handle Start [event=%x]", this));
00214 #endif
00215   nsIRequestObserver* receiver = (nsIRequestObserver*)mListener->GetReceiver();
00216   if (receiver == nsnull) {
00217       // must have already called OnStopRequest (it clears the receiver)
00218       return NS_ERROR_FAILURE;
00219   }
00220 
00221   nsresult status;
00222   nsresult rv = mRequest->GetStatus(&status);
00223   NS_ASSERTION(NS_SUCCEEDED(rv), "GetStatus failed");
00224   rv = receiver->OnStartRequest(mRequest, mContext);
00225 
00226   return rv;
00227 }
00228 
00229 NS_IMETHODIMP 
00230 nsAsyncStreamObserver::OnStartRequest(nsIRequest *request, nsISupports* context)
00231 {
00232     nsresult rv;
00233     nsOnStartRequestEvent* event = 
00234         new nsOnStartRequestEvent(this, request, context);
00235     if (event == nsnull)
00236         return NS_ERROR_OUT_OF_MEMORY;
00237 
00238 #if defined(PR_LOGGING)
00239     PLEventQueue *equeue;
00240     mEventQueue->GetPLEventQueue(&equeue);
00241     char ts[80];
00242     sprintf(ts, "nsAsyncStreamObserver: Start [this=%lx queue=%lx",
00243             (long)this, (long)equeue);
00244     if (!gStreamEventLog)
00245       gStreamEventLog = PR_NewLogModule("netlibStreamEvent");
00246     PR_LOG(gStreamEventLog, PR_LOG_DEBUG,
00247            ("nsAsyncStreamObserver: Start [this=%x queue=%x event=%x]",
00248             this, equeue, event));
00249 #endif
00250     rv = event->Fire(mEventQueue);
00251     if (NS_FAILED(rv)) goto failed;
00252     return rv;
00253 
00254   failed:
00255     delete event;
00256     return rv;
00257 }
00258 
00260 //
00261 // OnStopRequest
00262 //
00264 
00265 class nsOnStopRequestEvent : public nsStreamListenerEvent
00266 {
00267 public:
00268     nsOnStopRequestEvent(nsAsyncStreamObserver* listener, 
00269                          nsISupports* context, nsIRequest* request)
00270         : nsStreamListenerEvent(listener, request, context),
00271           mStatus(NS_OK) {}
00272     virtual ~nsOnStopRequestEvent();
00273 
00274     nsresult Init(nsresult aStatus);
00275     NS_IMETHOD HandleEvent();
00276 
00277 protected:
00278     nsresult    mStatus;
00279 };
00280 
00281 nsOnStopRequestEvent::~nsOnStopRequestEvent()
00282 {
00283 }
00284 
00285 nsresult
00286 nsOnStopRequestEvent::Init(nsresult aStatus)
00287 {
00288     mStatus = aStatus;
00289     return NS_OK;
00290 }
00291 
00292 NS_IMETHODIMP
00293 nsOnStopRequestEvent::HandleEvent()
00294 {
00295 #if defined(PR_LOGGING)
00296     if (!gStreamEventLog)
00297         gStreamEventLog = PR_NewLogModule("netlibStreamEvent");
00298     PR_LOG(gStreamEventLog, PR_LOG_DEBUG,
00299            ("netlibEvent: Handle Stop [event=%x]", this));
00300 #endif
00301     nsIRequestObserver* receiver = (nsIRequestObserver*)mListener->GetReceiver();
00302     if (receiver == nsnull) {
00303         // must have already called OnStopRequest (it clears the receiver)
00304         return NS_ERROR_FAILURE;
00305     }
00306 
00307     nsresult status = NS_OK;
00308     nsresult rv = mRequest->GetStatus(&status);
00309     NS_ASSERTION(NS_SUCCEEDED(rv), "GetStatus failed");
00310 
00311     //
00312     // If the consumer returned a failure code, then pass it out in the
00313     // OnStopRequest(...) notification...
00314     //
00315     if (NS_SUCCEEDED(rv) && NS_FAILED(status)) {
00316         mStatus = status;
00317     }
00318     rv = receiver->OnStopRequest(mRequest, mContext, mStatus);
00319     // Call clear on the listener to make sure it's cleanup is done on the correct thread
00320     mListener->Clear();
00321     return rv;
00322 }
00323 
00324 NS_IMETHODIMP 
00325 nsAsyncStreamObserver::OnStopRequest(nsIRequest* request, nsISupports* context,
00326                                      nsresult aStatus)
00327 {
00328     nsresult rv;
00329 
00330     //
00331     // Fire the OnStopRequest(...) regardless of what the current
00332     // Status is...
00333     //
00334     nsOnStopRequestEvent* event = 
00335         new nsOnStopRequestEvent(this, context, request);
00336     if (event == nsnull)
00337         return NS_ERROR_OUT_OF_MEMORY;
00338 
00339     rv = event->Init(aStatus);
00340     if (NS_FAILED(rv)) goto failed;
00341 #if defined(PR_LOGGING)
00342     PLEventQueue *equeue;
00343     mEventQueue->GetPLEventQueue(&equeue);
00344     if (!gStreamEventLog)
00345       gStreamEventLog = PR_NewLogModule("netlibStreamEvent");
00346     PR_LOG(gStreamEventLog, PR_LOG_DEBUG,
00347            ("nsAsyncStreamObserver: Stop [this=%x queue=%x event=%x]",
00348             this, equeue, event));
00349 #endif
00350     rv = event->Fire(mEventQueue);
00351     if (NS_FAILED(rv)) goto failed;
00352     return rv;
00353 
00354   failed:
00355     delete event;
00356     return rv;
00357 }
00358 
00360 //
00361 // OnDataAvailable
00362 //
00364 
00365 class nsOnDataAvailableEvent : public nsStreamListenerEvent
00366 {
00367 public:
00368     nsOnDataAvailableEvent(nsAsyncStreamObserver* listener, 
00369                            nsIRequest* request, nsISupports* context)
00370         : nsStreamListenerEvent(listener, request, context),
00371           mIStream(nsnull), mLength(0) {}
00372     virtual ~nsOnDataAvailableEvent();
00373 
00374     nsresult Init(nsIInputStream* aIStream, PRUint32 aSourceOffset,
00375                   PRUint32 aLength);
00376     NS_IMETHOD HandleEvent();
00377 
00378 protected:
00379     nsIInputStream*       mIStream;
00380     PRUint32                    mSourceOffset;
00381     PRUint32                    mLength;
00382 };
00383 
00384 nsOnDataAvailableEvent::~nsOnDataAvailableEvent()
00385 {
00386     NS_RELEASE(mIStream);
00387 }
00388 
00389 nsresult
00390 nsOnDataAvailableEvent::Init(nsIInputStream* aIStream, PRUint32 aSourceOffset,
00391                              PRUint32 aLength)
00392 {
00393     mSourceOffset = aSourceOffset;
00394     mLength = aLength;
00395     mIStream = aIStream;
00396     NS_ADDREF(mIStream);
00397     return NS_OK;
00398 }
00399 
00400 NS_IMETHODIMP
00401 nsOnDataAvailableEvent::HandleEvent()
00402 {
00403 #if defined(PR_LOGGING)
00404   if (!gStreamEventLog)
00405     gStreamEventLog = PR_NewLogModule("netlibStreamEvent");
00406   PR_LOG(gStreamEventLog, PR_LOG_DEBUG,
00407          ("netlibEvent: Handle Data [event=%x]", this));
00408 #endif
00409   nsIStreamListener* receiver = (nsIStreamListener*)mListener->GetReceiver();
00410   if (receiver == nsnull) {
00411       // must have already called OnStopRequest (it clears the receiver)
00412       return NS_ERROR_FAILURE;
00413   }
00414 
00415   nsresult status;
00416   nsresult rv = mRequest->GetStatus(&status);
00417   NS_ASSERTION(NS_SUCCEEDED(rv), "GetStatus failed");
00418 
00419   //
00420   // Only send OnDataAvailable(... ) notifications if all previous calls
00421   // have succeeded...
00422   //
00423   if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(status)) {
00424     rv = receiver->OnDataAvailable(mRequest, mContext,
00425                                    mIStream, mSourceOffset, mLength);
00426   }
00427   else {
00428     NS_WARNING("not calling OnDataAvailable");
00429   }
00430   return rv;
00431 }
00432 
00433 NS_IMETHODIMP 
00434 nsAsyncStreamListener::OnDataAvailable(nsIRequest* request, nsISupports* context,
00435                                        nsIInputStream *aIStream, 
00436                                        PRUint32 aSourceOffset,
00437                                        PRUint32 aLength)
00438 {
00439     nsresult rv;
00440     nsOnDataAvailableEvent* event = 
00441         new nsOnDataAvailableEvent(this, request, context);
00442     if (event == nsnull)
00443         return NS_ERROR_OUT_OF_MEMORY;
00444 
00445     rv = event->Init(aIStream, aSourceOffset, aLength);
00446     if (NS_FAILED(rv)) goto failed;
00447 #if defined(PR_LOGGING)
00448     PLEventQueue *equeue;
00449     mEventQueue->GetPLEventQueue(&equeue);
00450     if (!gStreamEventLog)
00451       gStreamEventLog = PR_NewLogModule("netlibStreamEvent");
00452     PR_LOG(gStreamEventLog, PR_LOG_DEBUG,
00453            ("nsAsyncStreamObserver: Data [this=%x queue=%x event=%x]",
00454             this, equeue, event));
00455 #endif
00456     rv = event->Fire(mEventQueue);
00457     if (NS_FAILED(rv)) goto failed;
00458     return rv;
00459 
00460   failed:
00461     delete event;
00462     return rv;
00463 }
00464 
00466 
00467 NS_METHOD
00468 nsAsyncStreamObserver::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
00469 {
00470     if (aOuter)
00471         return NS_ERROR_NO_AGGREGATION;
00472     nsAsyncStreamObserver* l = new nsAsyncStreamObserver();
00473     if (l == nsnull)
00474         return NS_ERROR_OUT_OF_MEMORY;
00475     NS_ADDREF(l);
00476     nsresult rv = l->QueryInterface(aIID, aResult);
00477     NS_RELEASE(l);
00478     return rv;
00479 }
00480 
00481 NS_METHOD
00482 nsAsyncStreamListener::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
00483 {
00484     if (aOuter)
00485         return NS_ERROR_NO_AGGREGATION;
00486     nsAsyncStreamListener* l = new nsAsyncStreamListener();
00487     if (l == nsnull)
00488         return NS_ERROR_OUT_OF_MEMORY;
00489     NS_ADDREF(l);
00490     nsresult rv = l->QueryInterface(aIID, aResult);
00491     NS_RELEASE(l);
00492     return rv;
00493 }
00494