mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-06 00:55:37 +00:00
686 lines
16 KiB
C++
686 lines
16 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "License"); you may not use this file except in
|
|
* compliance with the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS"
|
|
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
|
* the License for the specific language governing rights and limitations
|
|
* under the License.
|
|
*
|
|
* The Original Code is Mozilla Communicator client code.
|
|
*
|
|
* The Initial Developer of the Original Code is Netscape Communications
|
|
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
|
* Netscape Communications Corporation. All Rights Reserved.
|
|
*/
|
|
|
|
#include "nscore.h"
|
|
#include "nsRepository.h"
|
|
|
|
#include "nspr.h"
|
|
#include "plevent.h"
|
|
#include "plstr.h"
|
|
|
|
#include "nsNetThread.h"
|
|
|
|
#include "nsIStreamListener.h"
|
|
#include "nsIInputStream.h"
|
|
#include "nsIURL.h"
|
|
#include "nsString.h"
|
|
|
|
extern "C" {
|
|
#include "mkutils.h"
|
|
#include "mkgeturl.h"
|
|
#include "mktrace.h"
|
|
#include "mkstream.h"
|
|
#include "cvchunk.h"
|
|
|
|
#include "fileurl.h"
|
|
#include "httpurl.h"
|
|
#include "ftpurl.h"
|
|
#include "abouturl.h"
|
|
#include "gophurl.h"
|
|
#include "fileurl.h"
|
|
#include "remoturl.h"
|
|
#include "netcache.h"
|
|
|
|
|
|
void RL_Init();
|
|
|
|
PUBLIC NET_StreamClass *
|
|
NET_NGLayoutConverter(FO_Present_Types format_out,
|
|
void *converter_obj,
|
|
URL_Struct *URL_s,
|
|
MWContext *context);
|
|
|
|
}; /* end of extern "C" */
|
|
|
|
#if defined(XP_PC)
|
|
void net_InitAsyncDNS();
|
|
#endif /* XP_PC */
|
|
|
|
|
|
/*
|
|
* Initialize our protocols
|
|
*/
|
|
|
|
extern "C" void NET_ClientProtocolInitialize()
|
|
{
|
|
NET_InitFileProtocol();
|
|
NET_InitHTTPProtocol();
|
|
NET_InitMemCacProtocol();
|
|
NET_InitFTPProtocol();
|
|
NET_InitAboutProtocol();
|
|
NET_InitGopherProtocol();
|
|
NET_InitRemoteProtocol();
|
|
}
|
|
|
|
nsresult NS_InitNetlib(void)
|
|
{
|
|
/* Initialize netlib with 32 sockets... */
|
|
NET_InitNetLib(0, 32);
|
|
|
|
/* Initialize the file extension -> content-type mappings */
|
|
NET_InitFileFormatTypes(nsnull, nsnull);
|
|
|
|
NET_FinishInitNetLib();
|
|
|
|
NET_RegisterContentTypeConverter("*", FO_CACHE_AND_NGLAYOUT, NULL,
|
|
NET_CacheConverter);
|
|
NET_RegisterContentTypeConverter("*", FO_NGLAYOUT, NULL,
|
|
NET_NGLayoutConverter);
|
|
NET_RegisterContentTypeConverter(APPLICATION_HTTP_INDEX, FO_NGLAYOUT,
|
|
NULL, NET_HTTPIndexFormatToHTMLConverter);
|
|
|
|
NET_RegisterUniversalEncodingConverter("chunked",
|
|
NULL,
|
|
NET_ChunkedDecoderStream);
|
|
RL_Init();
|
|
|
|
#if defined(XP_PC)
|
|
net_InitAsyncDNS();
|
|
#endif /* XP_PC */
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
nsNetlibThread::nsNetlibThread()
|
|
{
|
|
mIsNetlibThreadRunning = PR_FALSE;
|
|
mNetlibEventQueue = nsnull;
|
|
}
|
|
|
|
|
|
nsNetlibThread::~nsNetlibThread()
|
|
{
|
|
Stop();
|
|
}
|
|
|
|
|
|
nsresult nsNetlibThread::Start(void)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
#if defined(NETLIB_THREAD)
|
|
#if defined(NSPR20) && defined(DEBUG)
|
|
if (NETLIB==NULL) {
|
|
NETLIB = PR_NewLogModule("NETLIB");
|
|
}
|
|
#endif
|
|
/*
|
|
* Create the netlib thread and wait for it to initialize Netlib...
|
|
*/
|
|
PR_CEnterMonitor(this);
|
|
|
|
mThread = PR_CreateThread(PR_USER_THREAD,
|
|
nsNetlibThread::NetlibThreadMain,
|
|
this,
|
|
PR_PRIORITY_NORMAL,
|
|
PR_GLOBAL_THREAD,
|
|
PR_JOINABLE_THREAD,
|
|
4096);
|
|
|
|
/*
|
|
* The netlib thread will call PR_Notify on the monitor when Netlib has
|
|
* been initialized...
|
|
*/
|
|
PR_CWait(this, PR_INTERVAL_NO_TIMEOUT);
|
|
PR_CExitMonitor(this);
|
|
#else
|
|
/*
|
|
* Initialize Netlib...
|
|
*/
|
|
NS_InitNetlib();
|
|
#endif /* !NETLIB_THREAD */
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
nsresult nsNetlibThread::Stop(void)
|
|
{
|
|
#if defined(NETLIB_THREAD)
|
|
PR_CEnterMonitor(this);
|
|
|
|
if (PR_TRUE == mIsNetlibThreadRunning) {
|
|
mIsNetlibThreadRunning = PR_FALSE;
|
|
|
|
PR_CWait(this, PR_INTERVAL_NO_TIMEOUT);
|
|
}
|
|
PR_CExitMonitor(this);
|
|
|
|
#else
|
|
NET_ShutdownNetLib();
|
|
#endif /* !NETLIB_THREAD */
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
void nsNetlibThread::NetlibThreadMain(void *aParam)
|
|
{
|
|
nsNetlibThread* me = (nsNetlibThread*)aParam;
|
|
|
|
PR_CEnterMonitor(me);
|
|
|
|
me->mNetlibEventQueue = PL_CreateEventQueue("Netlib Event Queue", PR_GetCurrentThread());
|
|
if (nsnull == me->mNetlibEventQueue) {
|
|
PR_CNotify(me);
|
|
PR_CExitMonitor(me);
|
|
|
|
/* XXX: return error status... */
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Initialize netlib on the netlib thread...
|
|
*/
|
|
NS_InitNetlib();
|
|
|
|
me->mIsNetlibThreadRunning = PR_TRUE;
|
|
|
|
/*
|
|
* Notify the caller thread that Netlib is now initialized...
|
|
*/
|
|
PR_CNotify(me);
|
|
PR_CExitMonitor(me);
|
|
|
|
/*
|
|
* Call the platform specific main loop...
|
|
*/
|
|
me->NetlibMainLoop();
|
|
|
|
/*
|
|
* Netlib is being shutdown... Clean up and exit.
|
|
*/
|
|
PR_CEnterMonitor(me);
|
|
me->mIsNetlibThreadRunning = PR_FALSE;
|
|
|
|
/* Notify the main thread that the Netlib thread is no longer running...*/
|
|
PR_CNotify(me);
|
|
PR_CExitMonitor(me);
|
|
|
|
PL_DestroyEventQueue(me->mNetlibEventQueue);
|
|
me->mNetlibEventQueue = nsnull;
|
|
|
|
NET_ShutdownNetLib();
|
|
}
|
|
|
|
/*
|
|
* Platform specific main loop...
|
|
*/
|
|
#if defined(XP_PC)
|
|
void CALLBACK NetlibTimerProc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
|
|
{
|
|
(void) NET_PollSockets();
|
|
}
|
|
|
|
void nsNetlibThread::NetlibMainLoop(void)
|
|
{
|
|
UINT timerId;
|
|
|
|
/*
|
|
* Create a timer to periodically call NET_PollSockets(...)
|
|
*/
|
|
timerId = SetTimer(NULL, 0, 10, (TIMERPROC)NetlibTimerProc);
|
|
|
|
while (PR_TRUE == mIsNetlibThreadRunning) {
|
|
MSG msg;
|
|
|
|
if (GetMessage(&msg, NULL, 0, 0)) {
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
|
|
KillTimer(NULL, timerId);
|
|
}
|
|
|
|
#else
|
|
void nsNetlibThread::NetlibMainLoop()
|
|
{
|
|
PR_ASSERT(0);
|
|
}
|
|
#endif /* ! XP_PC */
|
|
|
|
|
|
/*
|
|
* Proxy implementation for the nsIStreamListener interface...
|
|
*/
|
|
|
|
class nsStreamListenerProxy : public nsIStreamListener
|
|
{
|
|
public:
|
|
nsStreamListenerProxy(nsIStreamListener* aListener);
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
NS_IMETHOD OnStartBinding(nsIURL* aURL, const char *aContentType);
|
|
NS_IMETHOD OnProgress(nsIURL* aURL, PRInt32 aProgress, PRInt32 aProgressMax);
|
|
NS_IMETHOD OnStatus(nsIURL* aURL, const nsString &aMsg);
|
|
NS_IMETHOD OnStopBinding(nsIURL* aURL, PRInt32 aStatus, const nsString &aMsg);
|
|
NS_IMETHOD GetBindInfo(nsIURL* aURL);
|
|
NS_IMETHOD OnDataAvailable(nsIURL* aURL, nsIInputStream *aIStream,
|
|
PRInt32 aLength);
|
|
|
|
void SetStatus(nsresult aStatus);
|
|
nsresult GetStatus();
|
|
|
|
nsIStreamListener* mRealListener;
|
|
|
|
protected:
|
|
virtual ~nsStreamListenerProxy();
|
|
|
|
private:
|
|
nsresult mStatus;
|
|
};
|
|
|
|
|
|
/*-------------------- Base Proxy Class ------------------------------------*/
|
|
|
|
struct ProxyEvent : public PLEvent
|
|
{
|
|
ProxyEvent(nsStreamListenerProxy* aProxy, nsIURL* aURL);
|
|
virtual ~ProxyEvent();
|
|
NS_IMETHOD HandleEvent() = 0;
|
|
void Fire(void);
|
|
|
|
static void PR_CALLBACK HandlePLEvent(PLEvent* aEvent);
|
|
static void PR_CALLBACK DestroyPLEvent(PLEvent* aEvent);
|
|
|
|
nsStreamListenerProxy* mProxy;
|
|
nsIURL* mURL;
|
|
};
|
|
|
|
ProxyEvent::ProxyEvent(nsStreamListenerProxy* aProxy, nsIURL* aURL)
|
|
{
|
|
mProxy = aProxy;
|
|
mURL = aURL;
|
|
|
|
NS_ADDREF(mProxy);
|
|
NS_ADDREF(mURL);
|
|
|
|
}
|
|
|
|
ProxyEvent::~ProxyEvent()
|
|
{
|
|
NS_RELEASE(mProxy);
|
|
NS_RELEASE(mURL);
|
|
}
|
|
|
|
void PR_CALLBACK ProxyEvent::HandlePLEvent(PLEvent* aEvent)
|
|
{
|
|
/*
|
|
* XXX: This is a dangerous cast since it must adjust the pointer
|
|
* to compensate for the vtable...
|
|
*/
|
|
nsresult rv;
|
|
ProxyEvent *ev = (ProxyEvent*)aEvent;
|
|
|
|
rv = ev->HandleEvent();
|
|
if (NS_FAILED(rv)) {
|
|
ev->mProxy->SetStatus(rv);
|
|
}
|
|
}
|
|
|
|
void PR_CALLBACK ProxyEvent::DestroyPLEvent(PLEvent* aEvent)
|
|
{
|
|
/*
|
|
* XXX: This is a dangerous cast since it must adjust the pointer
|
|
* to compensate for the vtable...
|
|
*/
|
|
ProxyEvent *ev = (ProxyEvent*)aEvent;
|
|
|
|
delete ev;
|
|
}
|
|
|
|
#if defined(XP_UNIX)
|
|
extern PLEventQueue* gWebShell_UnixEventQueue;
|
|
#endif
|
|
|
|
void ProxyEvent::Fire()
|
|
{
|
|
PLEventQueue* eventQueue;
|
|
|
|
PL_InitEvent(this, nsnull,
|
|
(PLHandleEventProc) ProxyEvent::HandlePLEvent,
|
|
(PLDestroyEventProc) ProxyEvent::DestroyPLEvent);
|
|
|
|
#if defined(XP_PC)
|
|
eventQueue = PL_GetMainEventQueue();
|
|
#elif defined(XP_UNIX)
|
|
eventQueue = gWebShell_UnixEventQueue;
|
|
#endif
|
|
|
|
PL_PostEvent(eventQueue, this);
|
|
}
|
|
|
|
/*-------------- OnStartBinding Proxy --------------------------------------*/
|
|
|
|
struct OnStartBindingProxyEvent : public ProxyEvent
|
|
{
|
|
OnStartBindingProxyEvent(nsStreamListenerProxy* aProxy, nsIURL* aURL,
|
|
const char *aContentType);
|
|
virtual ~OnStartBindingProxyEvent();
|
|
NS_IMETHOD HandleEvent();
|
|
|
|
char *mContentType;
|
|
};
|
|
|
|
OnStartBindingProxyEvent::OnStartBindingProxyEvent(nsStreamListenerProxy* aProxy,
|
|
nsIURL* aURL,
|
|
const char *aContentType)
|
|
: ProxyEvent(aProxy, aURL)
|
|
{
|
|
mContentType = PL_strdup(aContentType);
|
|
}
|
|
|
|
OnStartBindingProxyEvent::~OnStartBindingProxyEvent()
|
|
{
|
|
PR_Free(mContentType);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
OnStartBindingProxyEvent::HandleEvent()
|
|
{
|
|
return mProxy->mRealListener->OnStartBinding(mURL, mContentType);
|
|
}
|
|
|
|
|
|
/*-------------- OnProgress Proxy ------------------------------------------*/
|
|
|
|
struct OnProgressProxyEvent : public ProxyEvent
|
|
{
|
|
OnProgressProxyEvent(nsStreamListenerProxy* aProxy, nsIURL* aURL,
|
|
PRInt32 aProgress, PRInt32 aProgressMax);
|
|
NS_IMETHOD HandleEvent();
|
|
|
|
PRInt32 mProgress;
|
|
PRInt32 mProgressMax;
|
|
};
|
|
|
|
OnProgressProxyEvent::OnProgressProxyEvent(nsStreamListenerProxy* aProxy,
|
|
nsIURL* aURL,
|
|
PRInt32 aProgress,
|
|
PRInt32 aProgressMax)
|
|
: ProxyEvent(aProxy, aURL)
|
|
{
|
|
mProgress = aProgress;
|
|
mProgressMax = aProgressMax;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
OnProgressProxyEvent::HandleEvent()
|
|
{
|
|
return mProxy->mRealListener->OnProgress(mURL, mProgress, mProgressMax);
|
|
}
|
|
|
|
/*-------------- OnStatus Proxy --------------------------------------------*/
|
|
|
|
struct OnStatusProxyEvent : public ProxyEvent
|
|
{
|
|
OnStatusProxyEvent(nsStreamListenerProxy* aProxy, nsIURL* aURL,
|
|
const nsString& aMsg);
|
|
NS_IMETHOD HandleEvent();
|
|
|
|
nsString mMsg;
|
|
};
|
|
|
|
OnStatusProxyEvent::OnStatusProxyEvent(nsStreamListenerProxy* aProxy,
|
|
nsIURL* aURL,
|
|
const nsString& aMsg)
|
|
: ProxyEvent(aProxy, aURL)
|
|
{
|
|
mMsg = aMsg;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
OnStatusProxyEvent::HandleEvent()
|
|
{
|
|
return mProxy->mRealListener->OnStatus(mURL, mMsg);
|
|
}
|
|
|
|
|
|
/*-------------- OnStopBinding Proxy ---------------------------------------*/
|
|
|
|
struct OnStopBindingProxyEvent : public ProxyEvent
|
|
{
|
|
OnStopBindingProxyEvent(nsStreamListenerProxy* aProxy, nsIURL* aURL,
|
|
PRInt32 aStatus, const nsString& aMsg);
|
|
NS_IMETHOD HandleEvent();
|
|
|
|
PRInt32 mStatus;
|
|
nsString mMsg;
|
|
};
|
|
|
|
OnStopBindingProxyEvent::OnStopBindingProxyEvent(nsStreamListenerProxy* aProxy,
|
|
nsIURL* aURL,
|
|
PRInt32 aStatus,
|
|
const nsString& aMsg)
|
|
: ProxyEvent(aProxy, aURL)
|
|
{
|
|
mStatus = aStatus;
|
|
mMsg = aMsg;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
OnStopBindingProxyEvent::HandleEvent()
|
|
{
|
|
return mProxy->mRealListener->OnStopBinding(mURL, mStatus, mMsg);
|
|
}
|
|
|
|
|
|
/*-------------- OnDataAvailable Proxy -------------------------------------*/
|
|
|
|
struct OnDataAvailableProxyEvent : public ProxyEvent
|
|
{
|
|
OnDataAvailableProxyEvent(nsStreamListenerProxy* aProxy, nsIURL* aURL,
|
|
nsIInputStream* aStream, PRInt32 aLength);
|
|
virtual ~OnDataAvailableProxyEvent();
|
|
NS_IMETHOD HandleEvent();
|
|
|
|
nsIInputStream* mStream;
|
|
PRInt32 mLength;
|
|
};
|
|
|
|
OnDataAvailableProxyEvent::OnDataAvailableProxyEvent(nsStreamListenerProxy* aProxy,
|
|
nsIURL* aURL,
|
|
nsIInputStream* aStream,
|
|
PRInt32 aLength)
|
|
: ProxyEvent(aProxy, aURL)
|
|
{
|
|
mStream = aStream;
|
|
NS_ADDREF(mStream);
|
|
|
|
mLength = aLength;
|
|
}
|
|
|
|
OnDataAvailableProxyEvent::~OnDataAvailableProxyEvent()
|
|
{
|
|
NS_RELEASE(mStream);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
OnDataAvailableProxyEvent::HandleEvent()
|
|
{
|
|
return mProxy->mRealListener->OnDataAvailable(mURL, mStream, mLength);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
nsStreamListenerProxy::nsStreamListenerProxy(nsIStreamListener* aListener)
|
|
{
|
|
NS_INIT_REFCNT();
|
|
|
|
mRealListener = aListener;
|
|
NS_ADDREF(mRealListener);
|
|
|
|
mStatus = NS_OK;
|
|
}
|
|
|
|
|
|
void nsStreamListenerProxy::SetStatus(nsresult aStatus)
|
|
{
|
|
NS_LOCK_INSTANCE();
|
|
mStatus = aStatus;
|
|
NS_UNLOCK_INSTANCE();
|
|
}
|
|
|
|
|
|
nsresult nsStreamListenerProxy::GetStatus()
|
|
{
|
|
nsresult rv;
|
|
|
|
NS_LOCK_INSTANCE();
|
|
rv = mStatus;
|
|
NS_UNLOCK_INSTANCE();
|
|
|
|
return rv;
|
|
}
|
|
|
|
/*
|
|
* Implementation of threadsafe ISupports methods...
|
|
*/
|
|
static NS_DEFINE_IID(kIStreamListenerIID, NS_ISTREAMLISTENER_IID);
|
|
NS_IMPL_THREADSAFE_ISUPPORTS(nsStreamListenerProxy, kIStreamListenerIID);
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsStreamListenerProxy::OnStartBinding(nsIURL* aURL, const char *aContentType)
|
|
{
|
|
nsresult rv;
|
|
OnStartBindingProxyEvent* ev;
|
|
|
|
rv = GetStatus();
|
|
if (NS_SUCCEEDED(rv)) {
|
|
ev = new OnStartBindingProxyEvent(this, aURL, aContentType);
|
|
if (nsnull == ev) {
|
|
rv = NS_ERROR_OUT_OF_MEMORY;
|
|
} else {
|
|
ev->Fire();
|
|
}
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsStreamListenerProxy::OnProgress(nsIURL* aURL, PRInt32 aProgress,
|
|
PRInt32 aProgressMax)
|
|
{
|
|
OnProgressProxyEvent* ev;
|
|
nsresult rv;
|
|
|
|
rv = GetStatus();
|
|
if (NS_SUCCEEDED(rv)) {
|
|
ev = new OnProgressProxyEvent(this, aURL, aProgress, aProgressMax);
|
|
if (nsnull == ev) {
|
|
rv = NS_ERROR_OUT_OF_MEMORY;
|
|
} else {
|
|
ev->Fire();
|
|
}
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsStreamListenerProxy::OnStatus(nsIURL* aURL, const nsString &aMsg)
|
|
{
|
|
nsresult rv;
|
|
OnStatusProxyEvent* ev;
|
|
|
|
rv = GetStatus();
|
|
if (NS_SUCCEEDED(rv)) {
|
|
ev = new OnStatusProxyEvent(this, aURL, aMsg);
|
|
if (nsnull == ev) {
|
|
rv = NS_ERROR_OUT_OF_MEMORY;
|
|
} else {
|
|
ev->Fire();
|
|
}
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsStreamListenerProxy::OnStopBinding(nsIURL* aURL, PRInt32 aStatus,
|
|
const nsString &aMsg)
|
|
{
|
|
nsresult rv;
|
|
OnStopBindingProxyEvent* ev;
|
|
|
|
rv = GetStatus();
|
|
if (NS_SUCCEEDED(rv)) {
|
|
ev = new OnStopBindingProxyEvent(this, aURL, aStatus, aMsg);
|
|
if (nsnull == ev) {
|
|
rv = NS_ERROR_OUT_OF_MEMORY;
|
|
} else {
|
|
ev->Fire();
|
|
}
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
NS_IMETHODIMP
|
|
nsStreamListenerProxy::GetBindInfo(nsIURL* aURL)
|
|
{
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsStreamListenerProxy::OnDataAvailable(nsIURL* aURL, nsIInputStream *aIStream,
|
|
PRInt32 aLength)
|
|
{
|
|
nsresult rv;
|
|
OnDataAvailableProxyEvent* ev;
|
|
|
|
rv = GetStatus();
|
|
if (NS_SUCCEEDED(rv)) {
|
|
ev = new OnDataAvailableProxyEvent(this, aURL, aIStream, aLength);
|
|
if (nsnull == ev) {
|
|
rv = NS_ERROR_OUT_OF_MEMORY;
|
|
} else {
|
|
ev->Fire();
|
|
}
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
|
|
nsStreamListenerProxy::~nsStreamListenerProxy()
|
|
{
|
|
NS_RELEASE(mRealListener);
|
|
}
|
|
|
|
nsIStreamListener* ns_NewStreamListenerProxy(nsIStreamListener* aListener)
|
|
{
|
|
return new nsStreamListenerProxy(aListener);
|
|
}
|