/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * 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. */ #ifdef XP_MAC #include "nsIDocumentLoader.h" #define NS_IMPL_IDS #else #define NS_IMPL_IDS #include "nsIDocumentLoader.h" #endif #include "prmem.h" #include "plstr.h" #include "nsString.h" #include "nsISupportsArray.h" #include "nsIURL.h" #include "nsIStreamListener.h" #include "nsINetSupport.h" #include "nsIPostToServer.h" #include "nsIFactory.h" #include "nsIContentViewerContainer.h" #include "nsIRefreshUrl.h" #include "nsITimer.h" #include "nsIDocumentLoaderObserver.h" #include "nsIDocumentLoadInfo.h" #include "nsVoidArray.h" #include "nsIHttpUrl.h" #include "nsILoadAttribs.h" // XXX: Only needed for dummy factory... #include "nsIDocument.h" #include "nsIDocumentViewer.h" #include "nsICSSParser.h" #include "nsLayoutCID.h" /* Forward declarations.... */ class nsDocLoaderImpl; /* Private IIDs... */ /* eb001fa0-214f-11d2-bec0-00805f8a66dc */ #define NS_DOCUMENTBINDINFO_IID \ { 0xeb001fa0, 0x214f, 0x11d2, \ {0xbe, 0xc0, 0x00, 0x80, 0x5f, 0x8a, 0x66, 0xdc} } /* 28475a80-2150-11d2-bec0-00805f8a66dc */ #define NS_DOCLOADERIMPL_IID \ { 0x28475a80, 0x2150, 0x11d2, \ {0xbe, 0xc0, 0x00, 0x80, 0x5f, 0x8a, 0x66, 0xdc} } /* Define IIDs... */ NS_DEFINE_IID(kIStreamObserverIID, NS_ISTREAMOBSERVER_IID); NS_DEFINE_IID(kIDocumentLoaderIID, NS_IDOCUMENTLOADER_IID); NS_DEFINE_IID(kIDocumentLoaderFactoryIID, NS_IDOCUMENTLOADERFACTORY_IID); NS_DEFINE_IID(kDocLoaderImplIID, NS_DOCLOADERIMPL_IID); NS_DEFINE_IID(kDocumentBindInfoIID, NS_DOCUMENTBINDINFO_IID); NS_DEFINE_IID(kIDocumentLoadInfoIID, NS_IDOCUMENTLOADINFO_IID); NS_DEFINE_IID(kRefreshURLIID, NS_IREFRESHURL_IID); NS_DEFINE_IID(kHTTPURLIID, NS_IHTTPURL_IID); NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); NS_DEFINE_IID(kIDocumentIID, NS_IDOCUMENT_IID); NS_DEFINE_IID(kCHTMLDocumentCID, NS_HTMLDOCUMENT_CID); NS_DEFINE_IID(kCImageDocumentCID, NS_IMAGEDOCUMENT_CID); NS_DEFINE_IID(kIStreamListenerIID, NS_ISTREAMLISTENER_IID); /* * The nsDocumentBindInfo contains the state required when a single document * is being loaded... Each instance remains alive until its target URL has * been loaded (or aborted). * * The Document Loader maintains a list of nsDocumentBindInfo instances which * represents the set of documents actively being loaded... */ class nsDocumentBindInfo : public nsIStreamListener, public nsINetSupport, public nsIRefreshUrl, public nsIDocumentLoadInfo { public: nsDocumentBindInfo(); nsresult Init(nsDocLoaderImpl* aDocLoader, const char *aCommand, nsIContentViewerContainer* aContainer, nsISupports* aExtraInfo, nsIStreamObserver* anObserver); NS_DECL_ISUPPORTS nsresult Bind(const nsString& aURLSpec, nsIPostData* aPostData, nsIStreamListener* aListener, PRInt32 type = 0, nsILoadAttribs* aLoadAttrib = nsnull); nsresult Stop(void); /* nsIStreamListener interface methods... */ NS_IMETHOD GetBindInfo(nsIURL* aURL); NS_IMETHOD OnProgress(nsIURL* aURL, PRInt32 aProgress, PRInt32 aProgressMax); NS_IMETHOD OnStatus(nsIURL* aURL, const nsString& aMsg); NS_IMETHOD OnStartBinding(nsIURL* aURL, const char *aContentType); NS_IMETHOD OnDataAvailable(nsIURL* aURL, nsIInputStream *aStream, PRInt32 aLength); NS_IMETHOD OnStopBinding(nsIURL* aURL, PRInt32 aStatus, const nsString& aMsg); /* nsINetSupport interface methods */ NS_IMETHOD_(void) Alert(const nsString &aText); NS_IMETHOD_(PRBool) Confirm(const nsString &aText); NS_IMETHOD_(PRBool) Prompt(const nsString &aText, const nsString &aDefault, nsString &aResult); NS_IMETHOD_(PRBool) PromptUserAndPassword(const nsString &aText, nsString &aUser, nsString &aPassword); NS_IMETHOD_(PRBool) PromptPassword(const nsString &aText, nsString &aPassword); nsresult GetStatus(void) { return mStatus; } /* nsIDocumentLoadInfo interface methods */ NS_IMETHOD GetCommand(nsString &aCommand); NS_IMETHOD GetURL(nsIURL **aURL); NS_IMETHOD GetContainer(nsIContentViewerContainer **aContainer); NS_IMETHOD GetExtraInfo(nsISupports **aExtraInfo); /* nsIRefreshURL interface methods... */ NS_IMETHOD RefreshURL(nsIURL* aURL, PRInt32 millis, PRBool repeat); NS_IMETHOD CancelRefreshURLTimers(void); protected: virtual ~nsDocumentBindInfo(); protected: char* m_Command; nsIURL* m_Url; nsIContentViewerContainer* m_Container; nsISupports* m_ExtraInfo; nsIStreamObserver* m_Observer; nsINetSupport* m_NetSupport; nsIStreamListener* m_NextStream; nsDocLoaderImpl* m_DocLoader; nsresult mStatus; }; /**************************************************************************** * nsDocFactoryImpl implementation... ****************************************************************************/ class nsDocFactoryImpl : public nsIDocumentLoaderFactory { public: nsDocFactoryImpl(); NS_DECL_ISUPPORTS NS_IMETHOD CreateInstance(nsIURL* aURL, const char* aContentType, const char* aCommand, nsIContentViewerContainer* aContainer, nsIStreamListener** aDocListener, nsIContentViewer** aDocViewer); nsresult InitUAStyleSheet(); nsresult CreateImageDocument(nsIURL* aURL, const char* aCommand, nsIContentViewerContainer* aContainer, nsIStreamListener** aDocListener, nsIContentViewer** aDocViewer); nsresult CreatePluginDocument(nsIURL* aURL, const char* aCommand, const char* aContentType, nsIContentViewerContainer* aContainer, nsIStreamListener** aDocListener, nsIContentViewer** aDocViewer); }; static nsIStyleSheet* gUAStyleSheet; nsDocFactoryImpl::nsDocFactoryImpl() { NS_INIT_REFCNT(); } /* * Implementation of ISupports methods... */ NS_IMPL_ISUPPORTS(nsDocFactoryImpl,kIDocumentLoaderFactoryIID); static char* gValidTypes[] = {"text/html","text/xml","application/rtf",0}; static char* gImageTypes[] = {"image/gif", "image/jpeg", 0 }; static char* gPluginTypes[] = { "video/quicktime", "video/msvideo", "video/x-msvideo", "application/vnd.netfpx", "image/vnd.fpx", "model/vrml", "x-world/x-vrml", "audio/midi", "audio/x-midi", "audio/wav", "audio/x-wav", "audio/aiff", "audio/x-aiff", "audio/basic", 0 }; NS_IMETHODIMP nsDocFactoryImpl::CreateInstance(nsIURL* aURL, const char* aContentType, const char *aCommand, nsIContentViewerContainer* aContainer, nsIStreamListener** aDocListener, nsIContentViewer** aDocViewer) { nsresult rv = NS_ERROR_FAILURE; nsIDocument* doc = nsnull; nsIDocumentViewer* docv = nsnull; int typeIndex=0; while(gValidTypes[typeIndex]) { if (0== PL_strcmp(gValidTypes[typeIndex++], aContentType)) { goto nextstep; } } // Try image types typeIndex = 0; while(gImageTypes[typeIndex]) { if (0== PL_strcmp(gImageTypes[typeIndex++], aContentType)) { return CreateImageDocument(aURL, aCommand, aContainer, aDocListener, aDocViewer); } } // Try plugin types typeIndex = 0; while(gPluginTypes[typeIndex]) { if (0== PL_strcmp(gPluginTypes[typeIndex++], aContentType)) { return CreatePluginDocument(aURL, aCommand, aContentType, aContainer, aDocListener, aDocViewer); } } goto done; nextstep: // Load the UA style sheet if we haven't already done that if (nsnull == gUAStyleSheet) { InitUAStyleSheet(); } /* * Create the HTML document... */ rv = nsRepository::CreateInstance(kCHTMLDocumentCID, nsnull, kIDocumentIID, (void **)&doc); if (NS_OK != rv) { goto done; } /* * Create the HTML Content Viewer... */ rv = NS_NewDocumentViewer(docv); if (NS_OK != rv) { goto done; } docv->SetUAStyleSheet(gUAStyleSheet); /* * Initialize the document to begin loading the data... * * An nsIStreamListener connected to the parser is returned in * aDocListener. */ rv = doc->StartDocumentLoad(aURL, aContainer, aDocListener); if (NS_OK != rv) { NS_IF_RELEASE(docv); goto done; } /* * Bind the document to the Content Viewer... */ rv = docv->BindToDocument(doc, aCommand); *aDocViewer = docv; done: NS_IF_RELEASE(doc); return rv; } nsresult nsDocFactoryImpl::CreateImageDocument(nsIURL* aURL, const char* aCommand, nsIContentViewerContainer* aContainer, nsIStreamListener** aDocListener, nsIContentViewer** aDocViewer) { nsresult rv = NS_ERROR_FAILURE; nsIDocument* doc = nsnull; nsIDocumentViewer* docv = nsnull; // Load the UA style sheet if we haven't already done that if (nsnull == gUAStyleSheet) { InitUAStyleSheet(); } /* * Create the image document... */ rv = nsRepository::CreateInstance(kCImageDocumentCID, nsnull, kIDocumentIID, (void **)&doc); if (NS_OK != rv) { goto done; } /* * Create the image content viewer... */ rv = NS_NewDocumentViewer(docv); if (NS_OK != rv) { goto done; } docv->SetUAStyleSheet(gUAStyleSheet); /* * Initialize the document to begin loading the data... * * An nsIStreamListener connected to the parser is returned in * aDocListener. */ rv = doc->StartDocumentLoad(aURL, aContainer, aDocListener); if (NS_OK != rv) { NS_IF_RELEASE(docv); goto done; } /* * Bind the document to the Content Viewer... */ rv = docv->BindToDocument(doc, aCommand); *aDocViewer = docv; done: NS_IF_RELEASE(doc); return rv; } extern nsresult NS_NewPluginContentViewer(const char* aCommand, nsIStreamListener** aDocListener, nsIContentViewer** aDocViewer); nsresult nsDocFactoryImpl::CreatePluginDocument(nsIURL* aURL, const char* aCommand, const char* aContentType, nsIContentViewerContainer* aContainer, nsIStreamListener** aDocListener, nsIContentViewer** aDocViewer) { /* * Create the plugin content viewer and stream listener... */ nsresult rv = NS_NewPluginContentViewer(aCommand, aDocListener, aDocViewer); return rv; } #define UA_CSS_URL "resource:/res/ua.css" nsresult nsDocFactoryImpl::InitUAStyleSheet() { nsresult rv = NS_OK; if (nsnull == gUAStyleSheet) { // snarf one nsIURL* uaURL; rv = NS_NewURL(&uaURL, nsnull, nsString(UA_CSS_URL)); // XXX this bites, fix it if (NS_OK == rv) { // Get an input stream from the url PRInt32 ec; nsIInputStream* in = uaURL->Open(&ec); if (nsnull != in) { // Translate the input using the argument character set id into unicode nsIUnicharInputStream* uin; rv = NS_NewConverterStream(&uin, nsnull, in); if (NS_OK == rv) { // Create parser and set it up to process the input file nsICSSParser* css; rv = NS_NewCSSParser(&css); if (NS_OK == rv) { // Parse the input and produce a style set // XXX note: we are ignoring rv until the error code stuff in the // input routines is converted to use nsresult's css->Parse(uin, uaURL, gUAStyleSheet); NS_RELEASE(css); } NS_RELEASE(uin); } NS_RELEASE(in); } else { // printf("open of %s failed: error=%x\n", UA_CSS_URL, ec); rv = NS_ERROR_ILLEGAL_VALUE; // XXX need a better error code here } NS_RELEASE(uaURL); } } return rv; } /**************************************************************************** * nsDocLoaderImpl implementation... ****************************************************************************/ class nsDocLoaderImpl : public nsIDocumentLoader { public: nsDocLoaderImpl(); NS_DECL_ISUPPORTS NS_IMETHOD LoadURL(const nsString& aURLSpec, const char *aCommand, nsIContentViewerContainer* aContainer, nsIPostData* aPostData = nsnull, nsISupports* aExtraInfo = nsnull, nsIStreamObserver* anObserver = nsnull, PRInt32 type = 0, const PRUint32 aLocalIP = 0); NS_IMETHOD LoadURL(const nsString& aURLSpec, nsIStreamListener* aListener); NS_IMETHOD Stop(void); NS_IMETHOD CreateDocumentLoader(nsIDocumentLoader** anInstance); NS_IMETHOD SetDocumentFactory(nsIDocumentLoaderFactory* aFactory); void LoadURLComplete(nsISupports* loader); NS_IMETHOD AddObserver(nsIDocumentLoaderObserver *aObserver); NS_IMETHOD RemoveObserver(nsIDocumentLoaderObserver *aObserver); void SetParent(nsDocLoaderImpl* aParent) { // XXX keeping a ref on our parent when our parent has a ref // on us is bad. NS_IF_RELEASE(mParent); mParent = aParent; NS_IF_ADDREF(aParent); } protected: virtual ~nsDocLoaderImpl(); private: static PRBool StopBindInfoEnumerator (nsISupports* aElement, void* aData); static PRBool StopDocLoaderEnumerator(nsISupports* aElement, void* aData); public: nsIDocumentLoaderFactory* m_DocFactory; protected: nsISupportsArray* m_LoadingDocsList; nsDocLoaderImpl* mParent; nsISupportsArray* mChildDocLoaderList; nsVoidArray mObservers; nsILoadAttribs* m_LoadAttrib; }; nsDocLoaderImpl::nsDocLoaderImpl() { NS_INIT_REFCNT(); NS_NewISupportsArray(&m_LoadingDocsList); NS_NewISupportsArray(&mChildDocLoaderList); mParent = nsnull; m_LoadAttrib = nsnull; m_DocFactory = new nsDocFactoryImpl(); NS_ADDREF(m_DocFactory); } nsDocLoaderImpl::~nsDocLoaderImpl() { Stop(); NS_IF_RELEASE(mParent); NS_IF_RELEASE(mChildDocLoaderList); NS_IF_RELEASE(m_LoadingDocsList); NS_IF_RELEASE(m_DocFactory); NS_IF_RELEASE(m_LoadAttrib); } /* * Implementation of ISupports methods... */ NS_IMPL_ADDREF(nsDocLoaderImpl); NS_IMPL_RELEASE(nsDocLoaderImpl); NS_IMETHODIMP nsDocLoaderImpl::QueryInterface(REFNSIID aIID, void** aInstancePtr) { if (NULL == aInstancePtr) { return NS_ERROR_NULL_POINTER; } if (aIID.Equals(kIDocumentLoaderIID)) { *aInstancePtr = (void*)(nsIDocumentLoader*)this; NS_ADDREF_THIS(); return NS_OK; } if (aIID.Equals(kDocLoaderImplIID)) { *aInstancePtr = (void*)this; NS_ADDREF_THIS(); return NS_OK; } return NS_NOINTERFACE; } NS_IMETHODIMP nsDocLoaderImpl::CreateDocumentLoader(nsIDocumentLoader** anInstance) { nsDocLoaderImpl* newLoader = nsnull; nsresult rv = NS_OK; /* Check for initial error conditions... */ if (nsnull == anInstance) { rv = NS_ERROR_NULL_POINTER; goto done; } NS_NEWXPCOM(newLoader, nsDocLoaderImpl); if (nsnull == newLoader) { rv = NS_ERROR_OUT_OF_MEMORY; goto done; } newLoader->SetParent(this); rv = newLoader->QueryInterface(kIDocumentLoaderIID, (void**)anInstance); mChildDocLoaderList->AppendElement(newLoader); done: return rv; } NS_IMETHODIMP nsDocLoaderImpl::SetDocumentFactory(nsIDocumentLoaderFactory* aFactory) { NS_IF_RELEASE(m_DocFactory); m_DocFactory = aFactory; NS_IF_ADDREF(m_DocFactory); return NS_OK; } NS_IMETHODIMP nsDocLoaderImpl::LoadURL(const nsString& aURLSpec, const char* aCommand, nsIContentViewerContainer* aContainer, nsIPostData* aPostData, nsISupports* aExtraInfo, nsIStreamObserver* anObserver, PRInt32 type, const PRUint32 aLocalIP) { nsresult rv; nsDocumentBindInfo* loader = nsnull; /* Check for initial error conditions... */ if (nsnull == aContainer) { rv = NS_ERROR_NULL_POINTER; goto done; } NS_NEWXPCOM(loader, nsDocumentBindInfo); if (nsnull == loader) { rv = NS_ERROR_OUT_OF_MEMORY; goto done; } loader->Init(this, // DocLoader aCommand, // Command aContainer, // Viewer Container aExtraInfo, // Extra Info anObserver); // Observer /* The DocumentBindInfo reference is only held by the Array... */ m_LoadingDocsList->AppendElement((nsIStreamListener *)loader); // If we've got special loading instructions, mind them. if ( (type == 2) || (type == 3) ) { if (!m_LoadAttrib) { rv = NS_NewLoadAttribs(&m_LoadAttrib); if (rv != NS_OK) return rv; } // type 2 and 3 correspond to proxy bypas m_LoadAttrib->SetBypassProxy(PR_TRUE); } if ( aLocalIP ) { if (!m_LoadAttrib) { rv = NS_NewLoadAttribs(&m_LoadAttrib); if (rv != NS_OK) return rv; } m_LoadAttrib->SetLocalIP(aLocalIP); } rv = loader->Bind(aURLSpec, aPostData, nsnull, type, m_LoadAttrib); done: return rv; } NS_IMETHODIMP nsDocLoaderImpl::LoadURL(const nsString& aURLSpec, nsIStreamListener* aListener) { nsresult rv; nsDocumentBindInfo* loader = nsnull; /* Check for initial error conditions... */ if (nsnull == aListener) { rv = NS_ERROR_NULL_POINTER; goto done; } NS_NEWXPCOM(loader, nsDocumentBindInfo); if (nsnull == loader) { rv = NS_ERROR_OUT_OF_MEMORY; goto done; } loader->Init(this, // DocLoader nsnull, // Command nsnull, // Viewer Container nsnull, // Extra Info nsnull); // Observer /* The DocumentBindInfo reference is only held by the Array... */ m_LoadingDocsList->AppendElement(((nsISupports*)(nsIStreamObserver*)loader)); rv = loader->Bind(aURLSpec, nsnull, aListener); done: return rv; } NS_IMETHODIMP nsDocLoaderImpl::Stop(void) { m_LoadingDocsList->EnumerateForwards(nsDocLoaderImpl::StopBindInfoEnumerator, nsnull); /* * Now the only reference to each nsDocumentBindInfo instance is held by * Netlib via the nsIStreamListener interface... * * When each connection is aborted, Netlib will release its reference to * the StreamListener and the DocumentBindInfo object will be deleted... */ m_LoadingDocsList->Clear(); /* * Now Stop() all documents being loaded by child DocumentLoaders... */ mChildDocLoaderList->EnumerateForwards(nsDocLoaderImpl::StopDocLoaderEnumerator, nsnull); return NS_OK; } void nsDocLoaderImpl::LoadURLComplete(nsISupports* aBindInfo) { PRBool rv; rv = m_LoadingDocsList->RemoveElement(aBindInfo); if (0 == m_LoadingDocsList->Count()) { PRInt32 count = mObservers.Count(); PRInt32 index; for (index = 0; index < count; index++) { nsIDocumentLoaderObserver* observer = (nsIDocumentLoaderObserver*)mObservers.ElementAt(index); observer->OnConnectionsComplete(); } } /* * If the entry was not found in the list, then it must have been cancelled * via Stop(...). */ #if defined(NS_DEBUG) if (PR_TRUE != rv) { nsDocumentBindInfo* docInfo; rv = aBindInfo->QueryInterface(kDocumentBindInfoIID, (void**)&docInfo); NS_ASSERTION(((NS_OK == rv) && (docInfo->GetStatus() == NS_BINDING_ABORTED)), "Entry was not Aborted!"); NS_IF_RELEASE(docInfo); } #endif /* NS_DEBUG */ } PRBool nsDocLoaderImpl::StopBindInfoEnumerator(nsISupports* aElement, void* aData) { nsresult rv; nsDocumentBindInfo* bindInfo; rv = aElement->QueryInterface(kDocumentBindInfoIID, (void**)&bindInfo); if (NS_OK == rv) { bindInfo->Stop(); NS_RELEASE(bindInfo); } return PR_TRUE; } PRBool nsDocLoaderImpl::StopDocLoaderEnumerator(nsISupports* aElement, void* aData) { nsresult rv; nsDocLoaderImpl* docLoader; rv = aElement->QueryInterface(kDocLoaderImplIID, (void**)&docLoader); if (NS_OK == rv) { docLoader->Stop(); } return PR_TRUE; } /* * Do not hold refs to the objects in the observer lists. Observers * are expected to remove themselves upon their destruction if they * have not removed themselves previously */ NS_IMETHODIMP nsDocLoaderImpl::AddObserver(nsIDocumentLoaderObserver* aObserver) { // Make sure the observer isn't already in the list if (mObservers.IndexOf(aObserver) == -1) { mObservers.AppendElement(aObserver); } return NS_OK; } NS_IMETHODIMP nsDocLoaderImpl::RemoveObserver(nsIDocumentLoaderObserver* aObserver) { if (PR_TRUE == mObservers.RemoveElement(aObserver)) { return NS_OK; } return NS_ERROR_FAILURE; } /**************************************************************************** * nsDocumentBindInfo implementation... ****************************************************************************/ nsDocumentBindInfo::nsDocumentBindInfo() { NS_INIT_REFCNT(); m_Command = nsnull; m_Url = nsnull; m_Container = nsnull; m_ExtraInfo = nsnull; m_Observer = nsnull; m_NetSupport = nsnull; m_NextStream = nsnull; m_DocLoader = nsnull; mStatus = NS_OK; } nsresult nsDocumentBindInfo::Init(nsDocLoaderImpl* aDocLoader, const char *aCommand, nsIContentViewerContainer* aContainer, nsISupports* aExtraInfo, nsIStreamObserver* anObserver) { m_Url = nsnull; m_NextStream = nsnull; m_Command = (nsnull != aCommand) ? PL_strdup(aCommand) : nsnull; m_ExtraInfo = aExtraInfo; m_DocLoader = aDocLoader; NS_ADDREF(m_DocLoader); m_Container = aContainer; NS_IF_ADDREF(m_Container); m_Observer = anObserver; NS_IF_ADDREF(m_Observer); m_NetSupport = NULL; if (m_Observer) { m_Observer->QueryInterface(kINetSupportIID, (void **) &m_NetSupport); } m_ExtraInfo = aExtraInfo; NS_IF_ADDREF(m_ExtraInfo); mStatus = NS_OK; return NS_OK; } nsDocumentBindInfo::~nsDocumentBindInfo() { if (m_Command) { PR_Free(m_Command); } m_Command = nsnull; NS_RELEASE (m_DocLoader); NS_IF_RELEASE(m_Url); NS_IF_RELEASE(m_NextStream); NS_IF_RELEASE(m_Container); NS_IF_RELEASE(m_Observer); NS_IF_RELEASE(m_NetSupport); NS_IF_RELEASE(m_ExtraInfo); } /* * Implementation of ISupports methods... */ NS_IMPL_ADDREF(nsDocumentBindInfo); NS_IMPL_RELEASE(nsDocumentBindInfo); nsresult nsDocumentBindInfo::QueryInterface(const nsIID& aIID, void** aInstancePtrResult) { NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer"); if (nsnull == aInstancePtrResult) { return NS_ERROR_NULL_POINTER; } *aInstancePtrResult = NULL; if (aIID.Equals(kIStreamObserverIID)) { *aInstancePtrResult = (void*) ((nsIStreamObserver*)this); NS_ADDREF_THIS(); return NS_OK; } if (aIID.Equals(kIStreamListenerIID)) { *aInstancePtrResult = (void*) ((nsIStreamListener*)this); NS_ADDREF_THIS(); return NS_OK; } if (aIID.Equals(kIDocumentLoadInfoIID)) { *aInstancePtrResult = (void*) ((nsIDocumentLoadInfo*)this); NS_ADDREF_THIS(); return NS_OK; } if (aIID.Equals(kDocumentBindInfoIID)) { *aInstancePtrResult = (void*) this; NS_ADDREF_THIS(); return NS_OK; } if (aIID.Equals(kINetSupportIID)) { *aInstancePtrResult = (void*) ((nsINetSupport*)this); NS_ADDREF_THIS(); return NS_OK; } if (aIID.Equals(kRefreshURLIID)) { *aInstancePtrResult = (void*) ((nsIRefreshUrl*)this); NS_ADDREF_THIS(); return NS_OK; } return NS_NOINTERFACE; } nsresult nsDocumentBindInfo::Bind(const nsString& aURLSpec, nsIPostData* aPostData, nsIStreamListener* aListener, PRInt32 type, nsILoadAttribs* aLoadAttrib) { nsresult rv; /* If this nsDocumentBindInfo was created with a container pointer. * extract the nsISupports iface from it and create the url with * the nsISupports pointer so the backend can have access to the front * end nsIContentViewerContainer for refreshing urls. */ if (m_Container) { rv = NS_NewURL(&m_Url, aURLSpec, m_Container); if (NS_OK != rv) { return rv; } } else { rv = NS_NewURL(&m_Url, aURLSpec); if (NS_OK != rv) { return rv; } } if (aLoadAttrib) m_Url->SetLoadAttribs(aLoadAttrib); rv = m_Url->SetReloadType(type); if (rv != NS_OK) { return rv; } /* Store any POST data into the URL */ if (nsnull != aPostData) { static NS_DEFINE_IID(kPostToServerIID, NS_IPOSTTOSERVER_IID); nsIPostToServer* pts; rv = m_Url->QueryInterface(kPostToServerIID, (void **)&pts); if (NS_OK == rv) { const char* data = aPostData->GetData(); if (aPostData->IsFile()) { pts->SendDataFromFile(data); } else { pts->SendData(data, aPostData->GetDataLength()); } } } /* Set up the stream listener (if provided)... */ if (nsnull != aListener) { m_NextStream = aListener; NS_ADDREF(m_NextStream); } /* Start the URL binding process... */ rv = m_Url->Open(this); return rv; } nsresult nsDocumentBindInfo::Stop(void) { mStatus = NS_BINDING_ABORTED; return NS_OK; } NS_METHOD nsDocumentBindInfo::GetBindInfo(nsIURL* aURL) { nsresult rv = NS_OK; NS_PRECONDITION(nsnull !=m_NextStream, "DocLoader: No stream for document"); if (nsnull != m_NextStream) { rv = m_NextStream->GetBindInfo(aURL); } return rv; } NS_METHOD nsDocumentBindInfo::OnProgress(nsIURL* aURL, PRInt32 aProgress, PRInt32 aProgressMax) { nsresult rv = NS_OK; /* Pass the notification out to the next stream listener... */ if (nsnull != m_NextStream) { rv = m_NextStream->OnProgress(aURL, aProgress, aProgressMax); } /* Pass the notification out to the Observer... */ if (nsnull != m_Observer) { /* XXX: Should we ignore the return value? */ (void) m_Observer->OnProgress(aURL, aProgress, aProgressMax); } return rv; } NS_METHOD nsDocumentBindInfo::OnStatus(nsIURL* aURL, const nsString& aMsg) { nsresult rv = NS_OK; /* Pass the notification out to the next stream listener... */ if (nsnull != m_NextStream) { rv = m_NextStream->OnStatus(aURL, aMsg); } /* Pass the notification out to the Observer... */ if (nsnull != m_Observer) { /* XXX: Should we ignore the return value? */ (void) m_Observer->OnStatus(aURL, aMsg); } return rv; } NS_METHOD nsDocumentBindInfo::OnStartBinding(nsIURL* aURL, const char *aContentType) { nsresult rv = NS_OK; nsIContentViewer* viewer = nsnull; /* If the binding has been canceled via Stop() then abort the load... */ if (NS_BINDING_ABORTED == mStatus) { rv = NS_BINDING_ABORTED; goto done; } if (nsnull == m_NextStream) { /* * Now that the content type is available, create a document (and viewer) * of the appropriate type... */ if (m_DocLoader->m_DocFactory) { rv = m_DocLoader->m_DocFactory->CreateInstance(m_Url, aContentType, m_Command, m_Container, &m_NextStream, &viewer); } else { rv = NS_ERROR_NULL_POINTER; } if (NS_OK != rv) { goto done; } /* * Give the document container the new viewer... */ viewer->SetContainer(m_Container); rv = m_Container->Embed(viewer, m_Command, m_ExtraInfo); if (NS_OK != rv) { goto done; } } /* * Pass the OnStartBinding(...) notification out to the document * IStreamListener. */ NS_ASSERTION((nsnull != m_NextStream), "No stream was created!"); if (nsnull != m_NextStream) { rv = m_NextStream->OnStartBinding(aURL, aContentType); } /* Pass the notification out to the Observer... */ if (nsnull != m_Observer) { /* XXX: Should we ignore the return value? */ (void) m_Observer->OnStartBinding(aURL, aContentType); } done: NS_IF_RELEASE(viewer); return rv; } NS_METHOD nsDocumentBindInfo::OnDataAvailable(nsIURL* aURL, nsIInputStream *aStream, PRInt32 aLength) { nsresult rv = NS_OK; /* If the binding has been canceled via Stop() then abort the load... */ if (NS_BINDING_ABORTED == mStatus) { rv = NS_BINDING_ABORTED; goto done; } NS_PRECONDITION(nsnull !=m_NextStream, "DocLoader: No stream for document"); if (nsnull != m_NextStream) { rv = m_NextStream->OnDataAvailable(aURL, aStream, aLength); } done: return rv; } NS_METHOD nsDocumentBindInfo::OnStopBinding(nsIURL* aURL, PRInt32 aStatus, const nsString& aMsg) { nsresult rv = NS_OK; if (nsnull != m_NextStream) { rv = m_NextStream->OnStopBinding(aURL, aStatus, aMsg); } /* Pass the notification out to the Observer... */ if (nsnull != m_Observer) { /* XXX: Should we ignore the return value? */ (void) m_Observer->OnStopBinding(aURL, aStatus, aMsg); } /* * The stream is complete... Tell the DocumentLoader to release us... */ m_DocLoader->LoadURLComplete((nsIStreamListener *)this); return rv; } NS_IMETHODIMP_(void) nsDocumentBindInfo::Alert(const nsString &aText) { if (nsnull != m_NetSupport) { m_NetSupport->Alert(aText); } } NS_IMETHODIMP_(PRBool) nsDocumentBindInfo::Confirm(const nsString &aText) { if (nsnull != m_NetSupport) { return m_NetSupport->Confirm(aText); } return PR_FALSE; } NS_IMETHODIMP_(PRBool) nsDocumentBindInfo::Prompt(const nsString &aText, const nsString &aDefault, nsString &aResult) { if (nsnull != m_NetSupport) { return m_NetSupport->Prompt(aText, aDefault, aResult); } return PR_FALSE; } NS_IMETHODIMP_(PRBool) nsDocumentBindInfo::PromptUserAndPassword(const nsString &aText, nsString &aUser, nsString &aPassword) { if (nsnull != m_NetSupport) { return m_NetSupport->PromptUserAndPassword(aText, aUser, aPassword); } return PR_FALSE; } NS_IMETHODIMP_(PRBool) nsDocumentBindInfo::PromptPassword(const nsString &aText, nsString &aPassword) { if (nsnull != m_NetSupport) { return m_NetSupport->PromptPassword(aText, aPassword); } return PR_FALSE; } NS_IMETHODIMP nsDocumentBindInfo::GetCommand(nsString &aCommand) { aCommand.SetString(m_Command); return NS_OK; } NS_IMETHODIMP nsDocumentBindInfo::GetURL(nsIURL **aURL) { *aURL = m_Url; NS_IF_ADDREF(m_Url); return NS_OK; } NS_IMETHODIMP nsDocumentBindInfo::GetContainer(nsIContentViewerContainer **aContainer) { *aContainer = m_Container; NS_IF_ADDREF(m_Container); return NS_OK; } NS_IMETHODIMP nsDocumentBindInfo::GetExtraInfo(nsISupports **aExtraInfo) { *aExtraInfo = m_ExtraInfo; NS_IF_ADDREF(m_ExtraInfo); return NS_OK; } NS_METHOD nsDocumentBindInfo::RefreshURL(nsIURL* aURL, PRInt32 millis, PRBool repeat) { if (nsnull != m_Container) { nsresult rv; nsIRefreshUrl* refresher = nsnull; /* Delegate the actual refresh call up-to the container. */ rv = m_Container->QueryInterface(kRefreshURLIID, (void**)&refresher); if (rv != NS_OK) { PR_FALSE; } rv = refresher->RefreshURL(aURL, millis, repeat); NS_RELEASE(refresher); return rv; } return PR_FALSE; } NS_METHOD nsDocumentBindInfo::CancelRefreshURLTimers(void) { if (nsnull != m_Container) { nsresult rv; nsIRefreshUrl* refresher = nsnull; /* Delegate the actual cancel call up-to the container. */ rv = m_Container->QueryInterface(kRefreshURLIID, (void**)&refresher); if (rv != NS_OK) { PR_FALSE; } rv = refresher->CancelRefreshURLTimers(); NS_RELEASE(refresher); return rv; } return PR_FALSE; } /******************************************* * nsDocLoaderFactory *******************************************/ static NS_DEFINE_IID(kIFactoryIID, NS_IFACTORY_IID); static NS_DEFINE_IID(kCDocumentLoader, NS_DOCUMENTLOADER_CID); class nsDocumentLoaderFactory : public nsIFactory { public: nsDocumentLoaderFactory(); NS_DECL_ISUPPORTS // nsIFactory methods NS_IMETHOD CreateInstance(nsISupports *aOuter, const nsIID &aIID, void **aResult); NS_IMETHOD LockFactory(PRBool aLock); protected: virtual ~nsDocumentLoaderFactory(); }; nsDocumentLoaderFactory::nsDocumentLoaderFactory() { NS_INIT_REFCNT(); } nsDocumentLoaderFactory::~nsDocumentLoaderFactory() { } /* * Implementation of ISupports methods... */ NS_IMPL_ISUPPORTS(nsDocumentLoaderFactory,kIFactoryIID); NS_IMETHODIMP nsDocumentLoaderFactory::CreateInstance(nsISupports* aOuter, const nsIID& aIID, void** aResult) { nsresult rv; nsIDocumentLoader* inst; static nsDocLoaderImpl* gGlobalDocLoader = nsnull; if (nsnull == aResult) { rv = NS_ERROR_NULL_POINTER; goto done; } *aResult = nsnull; if (nsnull != aOuter) { rv = NS_ERROR_NO_AGGREGATION; goto done; } if (nsnull == gGlobalDocLoader) { NS_NEWXPCOM(gGlobalDocLoader, nsDocLoaderImpl); if (nsnull == gGlobalDocLoader) { rv = NS_ERROR_OUT_OF_MEMORY; goto done; } NS_ADDREF(gGlobalDocLoader); // RefCount = 1 } rv = gGlobalDocLoader->CreateDocumentLoader(&inst); if (NS_OK != rv) { rv = NS_ERROR_OUT_OF_MEMORY; goto done; } *aResult = inst; done: return rv; } NS_IMETHODIMP nsDocumentLoaderFactory::LockFactory(PRBool aLock) { // Not implemented in simplest case. return NS_OK; } extern "C" NS_WEB nsresult NS_NewDocumentLoaderFactory(nsIFactory** aFactory) { if (nsnull == aFactory) { return NS_ERROR_NULL_POINTER; } nsDocumentLoaderFactory* it; NS_NEWXPCOM(it, nsDocumentLoaderFactory); *aFactory = it; if (nsnull == *aFactory) { return NS_ERROR_OUT_OF_MEMORY; } NS_ADDREF(*aFactory); return NS_OK; }