зеркало из https://github.com/mozilla/pjs.git
928 строки
24 KiB
C++
928 строки
24 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 "nsIComponentManager.h"
|
|
|
|
#include "nspr.h"
|
|
#include "plevent.h"
|
|
#include "plstr.h"
|
|
|
|
#include "nsNetThread.h"
|
|
|
|
#include "nsIEventQueueService.h"
|
|
#include "nsIStreamListener.h"
|
|
#include "nsIInputStream.h"
|
|
#include "nsIURL.h"
|
|
#include "nsString.h"
|
|
#include "nsIRelatedLinks.h"
|
|
|
|
extern "C" {
|
|
#include "sockstub.h"
|
|
#include "mkutils.h"
|
|
#include "mkgeturl.h"
|
|
#include "mktrace.h"
|
|
#include "mkstream.h"
|
|
#include "cvchunk.h"
|
|
#include "cvunzip.h"
|
|
#include "cvplugin.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"
|
|
|
|
#include "cvactive.h"
|
|
#include "nsCRT.h"
|
|
|
|
PUBLIC NET_StreamClass *
|
|
NET_NGLayoutConverter(FO_Present_Types format_out,
|
|
void *converter_obj,
|
|
URL_Struct *URL_s,
|
|
MWContext *context);
|
|
|
|
void net_AddrefContext(MWContext *context);
|
|
void net_ReleaseContext(MWContext *context);
|
|
} /* end of extern "C" */
|
|
|
|
#if defined(XP_PC)
|
|
void net_InitAsyncDNS();
|
|
#endif /* XP_PC */
|
|
|
|
|
|
PRThread* gNetlibThread = nsnull;
|
|
|
|
/*
|
|
* Initialize our protocols
|
|
*/
|
|
|
|
extern "C" void NET_ClientProtocolInitialize()
|
|
{
|
|
NET_InitSockStubProtocol();
|
|
NET_InitFileProtocol();
|
|
NET_InitHTTPProtocol();
|
|
#ifdef NU_CACHE
|
|
NET_InitNuCacheProtocol();
|
|
#else
|
|
NET_InitMemCacProtocol();
|
|
#endif
|
|
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_RegisterContentTypeConverter("text/*", FO_NGLAYOUT, NULL,
|
|
NET_PluginStream);
|
|
NET_RegisterContentTypeConverter("image/*", FO_NGLAYOUT, NULL,
|
|
NET_PluginStream);
|
|
NET_RegisterContentTypeConverter("application/*", FO_NGLAYOUT, NULL,
|
|
NET_PluginStream);
|
|
NET_RegisterContentTypeConverter(MESSAGE_RFC822, FO_NGLAYOUT, NULL,
|
|
NET_PluginStream);
|
|
|
|
NET_RegisterEncodingConverter(ENCODING_GZIP,
|
|
(void *) ENCODING_GZIP,
|
|
NET_UnZipConverter);
|
|
NET_RegisterEncodingConverter(ENCODING_GZIP2,
|
|
(void *) ENCODING_GZIP2,
|
|
NET_UnZipConverter);
|
|
|
|
NET_RegisterAllEncodingConverters("*", FO_NGLAYOUT);
|
|
|
|
NET_RegisterUniversalEncodingConverter("chunked",
|
|
NULL,
|
|
NET_ChunkedDecoderStream);
|
|
|
|
NET_RegisterContentTypeConverter("multipart/x-mixed-replace", FO_NGLAYOUT,
|
|
(void *) CVACTIVE_SIGNAL_AT_END_OF_MULTIPART,
|
|
CV_MakeMultipleDocumentStream);
|
|
|
|
NET_RegisterContentTypeConverter("multipart/mixed", FO_NGLAYOUT,
|
|
(void *) CVACTIVE_SIGNAL_AT_END_OF_MULTIPART,
|
|
CV_MakeMultipleDocumentStream);
|
|
|
|
|
|
#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);
|
|
NET_ReadCookies("");
|
|
#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();
|
|
gNetlibThread = PR_GetCurrentThread();
|
|
|
|
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(...)
|
|
*/
|
|
#if !defined(NO_NETWORK_POLLING)
|
|
timerId = SetTimer(NULL, 0, 10, (TIMERPROC)NetlibTimerProc);
|
|
#endif /* NO_NETWORK_POLLING */
|
|
|
|
while (PR_TRUE == mIsNetlibThreadRunning) {
|
|
MSG msg;
|
|
BOOL bIsMsg;
|
|
|
|
/*
|
|
* Block for network activity...
|
|
*
|
|
* If NET_CallingNetlibAllTheTime(...) is set, then do not block
|
|
* because a non-socket based protocol is being serviced (ie. file)
|
|
*/
|
|
if (NET_IsCallNetlibAllTheTimeSet(NULL, NULL)) {
|
|
NET_ProcessNet(NULL, NET_EVERYTIME_TYPE);
|
|
bIsMsg = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
|
|
} else {
|
|
bIsMsg = GetMessage(&msg, NULL, 0, 0);
|
|
}
|
|
|
|
if (FALSE != bIsMsg) {
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
|
|
#if !defined(NO_NETWORK_POLLING)
|
|
KillTimer(NULL, timerId);
|
|
#endif /* NO_NETWORK_POLLING */
|
|
}
|
|
|
|
#else
|
|
void nsNetlibThread::NetlibMainLoop()
|
|
{
|
|
while (mIsNetlibThreadRunning) {
|
|
if (NET_IsCallNetlibAllTheTimeSet(NULL, NULL))
|
|
NET_ProcessNet(NULL, NET_EVERYTIME_TYPE);
|
|
else
|
|
NET_PollSockets();
|
|
}
|
|
}
|
|
#endif /* ! XP_PC */
|
|
|
|
|
|
/*
|
|
* Proxy implementation for the nsIStreamListener interface...
|
|
*/
|
|
|
|
class nsStreamListenerProxy : public nsIStreamListener
|
|
{
|
|
public:
|
|
nsStreamListenerProxy(nsIStreamListener* aListener, nsIEventQueue* aEventQ);
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
NS_IMETHOD OnStartRequest(nsIURI* aURL, const char *aContentType);
|
|
NS_IMETHOD OnProgress(nsIURI* aURL, PRUint32 aProgress, PRUint32 aProgressMax);
|
|
NS_IMETHOD OnStatus(nsIURI* aURL, const PRUnichar* aMsg);
|
|
NS_IMETHOD OnStopRequest(nsIURI* aURL, nsresult aStatus, const PRUnichar* aMsg);
|
|
NS_IMETHOD GetBindInfo(nsIURI* aURL, nsStreamBindingInfo* info);
|
|
NS_IMETHOD OnDataAvailable(nsIURI* aURL, nsIInputStream *aIStream,
|
|
PRUint32 aLength);
|
|
|
|
void SetStatus(nsresult aStatus);
|
|
nsresult GetStatus();
|
|
|
|
nsIStreamListener* mRealListener;
|
|
|
|
protected:
|
|
virtual ~nsStreamListenerProxy();
|
|
|
|
private:
|
|
nsresult mStatus;
|
|
nsIEventQueue* mEventQ;
|
|
};
|
|
|
|
|
|
/*-------------------- Base Proxy Class ------------------------------------*/
|
|
|
|
struct ProxyEvent : public PLEvent
|
|
{
|
|
virtual ~ProxyEvent();
|
|
virtual void InitEvent();
|
|
NS_IMETHOD HandleEvent() = 0;
|
|
void Fire(nsIEventQueue* aEventQ);
|
|
|
|
static void PR_CALLBACK HandlePLEvent(PLEvent* aEvent);
|
|
static void PR_CALLBACK DestroyPLEvent(PLEvent* aEvent);
|
|
};
|
|
|
|
ProxyEvent::~ProxyEvent()
|
|
{
|
|
}
|
|
|
|
void ProxyEvent::InitEvent()
|
|
{
|
|
PL_InitEvent(this, nsnull,
|
|
(PLHandleEventProc) ProxyEvent::HandlePLEvent,
|
|
(PLDestroyEventProc) ProxyEvent::DestroyPLEvent);
|
|
}
|
|
|
|
void PR_CALLBACK ProxyEvent::HandlePLEvent(PLEvent* aEvent)
|
|
{
|
|
/*
|
|
* XXX: This is a dangerous cast since it must adjust the pointer
|
|
* to compensate for the vtable...
|
|
*/
|
|
ProxyEvent *ev = (ProxyEvent*)aEvent;
|
|
|
|
ev->HandleEvent();
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
void ProxyEvent::Fire(nsIEventQueue* aEventQ)
|
|
{
|
|
InitEvent();
|
|
|
|
NS_PRECONDITION(nsnull != aEventQ, "nsIEventQueue for thread is null");
|
|
|
|
aEventQ->PostEvent(this);
|
|
}
|
|
|
|
|
|
/*--------- Base Class for the nsIStreamListenerProxy Class ----------------*/
|
|
|
|
|
|
struct StreamListenerProxyEvent : public ProxyEvent
|
|
{
|
|
StreamListenerProxyEvent(nsStreamListenerProxy* aProxy, nsIURI* aURL);
|
|
virtual ~StreamListenerProxyEvent();
|
|
|
|
virtual void InitEvent();
|
|
static void PR_CALLBACK HandlePLEvent(PLEvent* aEvent);
|
|
|
|
nsStreamListenerProxy* mProxy;
|
|
nsIURI* mURL;
|
|
};
|
|
|
|
|
|
StreamListenerProxyEvent::StreamListenerProxyEvent(nsStreamListenerProxy* aProxy, nsIURI* aURL)
|
|
{
|
|
mProxy = aProxy;
|
|
mURL = aURL;
|
|
|
|
NS_IF_ADDREF(mProxy);
|
|
NS_IF_ADDREF(mURL);
|
|
|
|
}
|
|
|
|
StreamListenerProxyEvent::~StreamListenerProxyEvent()
|
|
{
|
|
NS_IF_RELEASE(mProxy);
|
|
NS_IF_RELEASE(mURL);
|
|
}
|
|
|
|
void StreamListenerProxyEvent::InitEvent()
|
|
{
|
|
PL_InitEvent(this, nsnull,
|
|
(PLHandleEventProc) StreamListenerProxyEvent::HandlePLEvent,
|
|
(PLDestroyEventProc) ProxyEvent::DestroyPLEvent);
|
|
}
|
|
|
|
void PR_CALLBACK StreamListenerProxyEvent::HandlePLEvent(PLEvent* aEvent)
|
|
{
|
|
/*
|
|
* XXX: This is a dangerous cast since it must adjust the pointer
|
|
* to compensate for the vtable...
|
|
*/
|
|
nsresult rv;
|
|
StreamListenerProxyEvent *ev = (StreamListenerProxyEvent*)aEvent;
|
|
|
|
rv = ev->HandleEvent();
|
|
if (NS_FAILED(rv)) {
|
|
ev->mProxy->SetStatus(rv);
|
|
}
|
|
}
|
|
|
|
/*-------------- OnStartRequest Proxy --------------------------------------*/
|
|
|
|
struct OnStartRequestProxyEvent : public StreamListenerProxyEvent
|
|
{
|
|
OnStartRequestProxyEvent(nsStreamListenerProxy* aProxy, nsIURI* aURL,
|
|
const char *aContentType);
|
|
virtual ~OnStartRequestProxyEvent();
|
|
NS_IMETHOD HandleEvent();
|
|
|
|
char *mContentType;
|
|
};
|
|
|
|
OnStartRequestProxyEvent::OnStartRequestProxyEvent(nsStreamListenerProxy* aProxy,
|
|
nsIURI* aURL,
|
|
const char *aContentType)
|
|
: StreamListenerProxyEvent(aProxy, aURL)
|
|
{
|
|
mContentType = PL_strdup(aContentType);
|
|
}
|
|
|
|
OnStartRequestProxyEvent::~OnStartRequestProxyEvent()
|
|
{
|
|
PR_Free(mContentType);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
OnStartRequestProxyEvent::HandleEvent()
|
|
{
|
|
return mProxy->mRealListener->OnStartRequest(mURL, mContentType);
|
|
}
|
|
|
|
|
|
/*-------------- OnProgress Proxy ------------------------------------------*/
|
|
|
|
struct OnProgressProxyEvent : public StreamListenerProxyEvent
|
|
{
|
|
OnProgressProxyEvent(nsStreamListenerProxy* aProxy, nsIURI* aURL,
|
|
PRUint32 aProgress, PRUint32 aProgressMax);
|
|
NS_IMETHOD HandleEvent();
|
|
|
|
PRUint32 mProgress;
|
|
PRUint32 mProgressMax;
|
|
};
|
|
|
|
OnProgressProxyEvent::OnProgressProxyEvent(nsStreamListenerProxy* aProxy,
|
|
nsIURI* aURL,
|
|
PRUint32 aProgress,
|
|
PRUint32 aProgressMax)
|
|
: StreamListenerProxyEvent(aProxy, aURL)
|
|
{
|
|
mProgress = aProgress;
|
|
mProgressMax = aProgressMax;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
OnProgressProxyEvent::HandleEvent()
|
|
{
|
|
return mProxy->mRealListener->OnProgress(mURL, mProgress, mProgressMax);
|
|
}
|
|
|
|
/*-------------- OnStatus Proxy --------------------------------------------*/
|
|
|
|
struct OnStatusProxyEvent : public StreamListenerProxyEvent
|
|
{
|
|
OnStatusProxyEvent(nsStreamListenerProxy* aProxy, nsIURI* aURL,
|
|
const PRUnichar* aMsg);
|
|
NS_IMETHOD HandleEvent();
|
|
|
|
PRUnichar* mMsg;
|
|
};
|
|
|
|
OnStatusProxyEvent::OnStatusProxyEvent(nsStreamListenerProxy* aProxy,
|
|
nsIURI* aURL,
|
|
const PRUnichar* aMsg)
|
|
: StreamListenerProxyEvent(aProxy, aURL)
|
|
{
|
|
mMsg = nsCRT::strdup(aMsg);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
OnStatusProxyEvent::HandleEvent()
|
|
{
|
|
nsresult rv = mProxy->mRealListener->OnStatus(mURL, mMsg);
|
|
delete []mMsg;
|
|
mMsg = nsnull;
|
|
return rv;
|
|
}
|
|
|
|
|
|
/*-------------- OnStopRequest Proxy ---------------------------------------*/
|
|
|
|
struct OnStopRequestProxyEvent : public StreamListenerProxyEvent
|
|
{
|
|
OnStopRequestProxyEvent(nsStreamListenerProxy* aProxy, nsIURI* aURL,
|
|
nsresult aStatus, const PRUnichar* aMsg);
|
|
NS_IMETHOD HandleEvent();
|
|
|
|
nsresult mStatus;
|
|
PRUnichar* mMsg;
|
|
};
|
|
|
|
OnStopRequestProxyEvent::OnStopRequestProxyEvent(nsStreamListenerProxy* aProxy,
|
|
nsIURI* aURL,
|
|
nsresult aStatus,
|
|
const PRUnichar* aMsg)
|
|
: StreamListenerProxyEvent(aProxy, aURL)
|
|
{
|
|
mStatus = aStatus;
|
|
mMsg = nsCRT::strdup(aMsg);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
OnStopRequestProxyEvent::HandleEvent()
|
|
{
|
|
nsresult rv = mProxy->mRealListener->OnStopRequest(mURL, mStatus, mMsg);
|
|
delete []mMsg;
|
|
mMsg = nsnull;
|
|
return rv;
|
|
}
|
|
|
|
|
|
/*-------------- OnDataAvailable Proxy -------------------------------------*/
|
|
|
|
struct OnDataAvailableProxyEvent : public StreamListenerProxyEvent
|
|
{
|
|
OnDataAvailableProxyEvent(nsStreamListenerProxy* aProxy, nsIURI* aURL,
|
|
nsIInputStream* aStream, PRUint32 aLength);
|
|
virtual ~OnDataAvailableProxyEvent();
|
|
NS_IMETHOD HandleEvent();
|
|
|
|
nsIInputStream* mStream;
|
|
PRUint32 mLength;
|
|
};
|
|
|
|
OnDataAvailableProxyEvent::OnDataAvailableProxyEvent(nsStreamListenerProxy* aProxy,
|
|
nsIURI* aURL,
|
|
nsIInputStream* aStream,
|
|
PRUint32 aLength)
|
|
: StreamListenerProxyEvent(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,
|
|
nsIEventQueue* aEventQ)
|
|
{
|
|
NS_INIT_REFCNT();
|
|
|
|
mRealListener = aListener;
|
|
NS_ADDREF(mRealListener);
|
|
|
|
mEventQ = aEventQ;
|
|
NS_IF_ADDREF(mEventQ);
|
|
|
|
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::OnStartRequest(nsIURI* aURL, const char *aContentType)
|
|
{
|
|
nsresult rv;
|
|
|
|
if (PR_GetCurrentThread() == gNetlibThread) {
|
|
OnStartRequestProxyEvent* ev;
|
|
|
|
rv = GetStatus();
|
|
if (NS_SUCCEEDED(rv)) {
|
|
ev = new OnStartRequestProxyEvent(this, aURL, aContentType);
|
|
if (nsnull == ev) {
|
|
rv = NS_ERROR_OUT_OF_MEMORY;
|
|
} else {
|
|
ev->Fire(mEventQ);
|
|
}
|
|
}
|
|
} else {
|
|
rv = mRealListener->OnStartRequest(aURL, aContentType);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsStreamListenerProxy::OnProgress(nsIURI* aURL, PRUint32 aProgress,
|
|
PRUint32 aProgressMax)
|
|
{
|
|
nsresult rv;
|
|
|
|
if (PR_GetCurrentThread() == gNetlibThread) {
|
|
OnProgressProxyEvent* ev;
|
|
/*
|
|
* Only fire the OnProgress notification if the connection is still valid.
|
|
* ie. A previous call did not fail...
|
|
*/
|
|
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(mEventQ);
|
|
}
|
|
}
|
|
} else {
|
|
rv = mRealListener->OnProgress(aURL, aProgress, aProgressMax);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsStreamListenerProxy::OnStatus(nsIURI* aURL, const PRUnichar* aMsg)
|
|
{
|
|
nsresult rv;
|
|
|
|
if (PR_GetCurrentThread() == gNetlibThread) {
|
|
OnStatusProxyEvent* ev;
|
|
/*
|
|
* Only fire the OnStatus notification if the connection is still valid.
|
|
* ie. A previous call did not fail...
|
|
*/
|
|
rv = GetStatus();
|
|
if (NS_SUCCEEDED(rv)) {
|
|
ev = new OnStatusProxyEvent(this, aURL, aMsg);
|
|
if (nsnull == ev) {
|
|
rv = NS_ERROR_OUT_OF_MEMORY;
|
|
} else {
|
|
ev->Fire(mEventQ);
|
|
}
|
|
}
|
|
} else {
|
|
rv = mRealListener->OnStatus(aURL, aMsg);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsStreamListenerProxy::OnStopRequest(nsIURI* aURL, nsresult aStatus,
|
|
const PRUnichar* aMsg)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
if (PR_GetCurrentThread() == gNetlibThread) {
|
|
OnStopRequestProxyEvent* ev;
|
|
/*
|
|
* Always fire the OnStopRequest notification...
|
|
*/
|
|
ev = new OnStopRequestProxyEvent(this, aURL, aStatus, aMsg);
|
|
if (nsnull == ev) {
|
|
rv = NS_ERROR_OUT_OF_MEMORY;
|
|
} else {
|
|
ev->Fire(mEventQ);
|
|
}
|
|
} else {
|
|
rv = mRealListener->OnStopRequest(aURL, aStatus, aMsg);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
NS_IMETHODIMP
|
|
nsStreamListenerProxy::GetBindInfo(nsIURI* aURL, nsStreamBindingInfo* info)
|
|
{
|
|
nsresult rv;
|
|
|
|
if (PR_GetCurrentThread() == gNetlibThread) {
|
|
PR_ASSERT(0);
|
|
rv = NS_ERROR_FAILURE;
|
|
} else {
|
|
rv = mRealListener->GetBindInfo(aURL, info);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsStreamListenerProxy::OnDataAvailable(nsIURI* aURL, nsIInputStream *aIStream,
|
|
PRUint32 aLength)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
if (PR_GetCurrentThread() == gNetlibThread) {
|
|
OnDataAvailableProxyEvent* ev;
|
|
/*
|
|
* Only fire the OnDataAvailable notification if the connection is still valid.
|
|
* ie. A previous call did not fail...
|
|
*/
|
|
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(mEventQ);
|
|
}
|
|
}
|
|
} else {
|
|
rv = mRealListener->OnDataAvailable(aURL, aIStream, aLength);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
|
|
nsStreamListenerProxy::~nsStreamListenerProxy()
|
|
{
|
|
NS_RELEASE(mRealListener);
|
|
NS_IF_RELEASE(mEventQ);
|
|
}
|
|
|
|
nsIStreamListener* ns_NewStreamListenerProxy(nsIStreamListener* aListener,
|
|
nsIEventQueue* aEventQ)
|
|
{
|
|
return new nsStreamListenerProxy(aListener, aEventQ);
|
|
}
|
|
|
|
|
|
/*----------- Proxy for net_CallExitRoutine(...) ---------------------------*/
|
|
extern "C" MODULE_PRIVATE void
|
|
net_CallExitRoutine(Net_GetUrlExitFunc* exit_routine,
|
|
URL_Struct* URL_s,
|
|
int status,
|
|
FO_Present_Types format_out,
|
|
MWContext* window_id);
|
|
|
|
|
|
struct CallExitRoutineProxyEvent : public ProxyEvent
|
|
{
|
|
CallExitRoutineProxyEvent(Net_GetUrlExitFunc* aExitRoutine,
|
|
URL_Struct* aURL_s,
|
|
int aStatus,
|
|
FO_Present_Types aFormatOut,
|
|
MWContext* aWindowId);
|
|
virtual ~CallExitRoutineProxyEvent();
|
|
NS_IMETHOD HandleEvent();
|
|
|
|
Net_GetUrlExitFunc* exit_routine;
|
|
URL_Struct* URL_s;
|
|
int status;
|
|
FO_Present_Types format_out;
|
|
MWContext* window_id;
|
|
};
|
|
|
|
CallExitRoutineProxyEvent::CallExitRoutineProxyEvent(Net_GetUrlExitFunc* aExitRoutine,
|
|
URL_Struct* aURL_s,
|
|
int aStatus,
|
|
FO_Present_Types aFormatOut,
|
|
MWContext* aWindowId)
|
|
{
|
|
exit_routine = aExitRoutine;
|
|
URL_s = aURL_s;
|
|
status = aStatus;
|
|
format_out = aFormatOut;
|
|
window_id = aWindowId;
|
|
|
|
net_AddrefContext(window_id);
|
|
NET_HoldURLStruct(URL_s);
|
|
}
|
|
|
|
|
|
CallExitRoutineProxyEvent::~CallExitRoutineProxyEvent()
|
|
{
|
|
NET_DropURLStruct(URL_s);
|
|
net_ReleaseContext(window_id);
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
CallExitRoutineProxyEvent::HandleEvent()
|
|
{
|
|
net_CallExitRoutine(exit_routine, URL_s, status, format_out, window_id);
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
extern "C" MODULE_PRIVATE void
|
|
net_CallExitRoutineProxy(Net_GetUrlExitFunc* exit_routine,
|
|
URL_Struct* URL_s,
|
|
int status,
|
|
FO_Present_Types format_out,
|
|
MWContext* window_id)
|
|
{
|
|
CallExitRoutineProxyEvent* ev;
|
|
|
|
/*
|
|
* Make sure that the URL_Struct was opened by the nsINetService...
|
|
* Otherwise, we cannot look at the URL_s->owner_data
|
|
*/
|
|
if (NULL != window_id->modular_data) {
|
|
/*
|
|
* Always use a PLEvent to call the exit_routine(...). This is necessary
|
|
* because when a connection is interrupted, the exit_routine(...) is called
|
|
* inside of the LIBNET_LOCK().
|
|
*
|
|
* By always using an event, we are sure that the exit_routine(...) is not
|
|
* called while the thread is holding the LIBNET_LOCK().
|
|
*/
|
|
ev = new CallExitRoutineProxyEvent(exit_routine, URL_s, status,
|
|
format_out, window_id);
|
|
if (nsnull != ev) {
|
|
|
|
nsIEventQueue* eventQueue = (nsIEventQueue*)(URL_s->owner_data);
|
|
if (eventQueue)
|
|
ev->Fire(eventQueue);
|
|
}
|
|
} else {
|
|
net_CallExitRoutine(exit_routine, URL_s, status, format_out, window_id);
|
|
}
|
|
}
|