michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "TestCommon.h" michael@0: #include michael@0: #ifdef WIN32 michael@0: #include michael@0: #endif michael@0: #include "nspr.h" michael@0: #include "nscore.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsIIOService.h" michael@0: #include "nsIServiceManager.h" michael@0: #include "nsIStreamListener.h" michael@0: #include "nsIInputStream.h" michael@0: #include "nsIChannel.h" michael@0: #include "nsIURL.h" michael@0: #include "nsIInterfaceRequestor.h" michael@0: #include "nsIInterfaceRequestorUtils.h" michael@0: #include "nsIDNSService.h" michael@0: #include "mozilla/Attributes.h" michael@0: michael@0: #include "nsISimpleEnumerator.h" michael@0: #include "nsNetUtil.h" michael@0: #include "nsStringAPI.h" michael@0: michael@0: static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID); michael@0: michael@0: static bool gError = false; michael@0: static int32_t gKeepRunning = 0; michael@0: michael@0: #define NS_IEQUALS_IID \ michael@0: { 0x11c5c8ee, 0x1dd2, 0x11b2, \ michael@0: { 0xa8, 0x93, 0xbb, 0x23, 0xa1, 0xb6, 0x27, 0x76 }} michael@0: michael@0: class nsIEquals : public nsISupports { michael@0: public: michael@0: NS_DECLARE_STATIC_IID_ACCESSOR(NS_IEQUALS_IID) michael@0: NS_IMETHOD Equals(void *aPtr, bool *_retval) = 0; michael@0: }; michael@0: michael@0: NS_DEFINE_STATIC_IID_ACCESSOR(nsIEquals, NS_IEQUALS_IID) michael@0: michael@0: class ConsumerContext MOZ_FINAL : public nsIEquals { michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: michael@0: ConsumerContext() { } michael@0: michael@0: NS_IMETHOD Equals(void *aPtr, bool *_retval) { michael@0: *_retval = true; michael@0: if (aPtr != this) *_retval = false; michael@0: return NS_OK; michael@0: } michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(ConsumerContext, nsIEquals) michael@0: michael@0: class Consumer : public nsIStreamListener { michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_NSIREQUESTOBSERVER michael@0: NS_DECL_NSISTREAMLISTENER michael@0: michael@0: Consumer(); michael@0: virtual ~Consumer(); michael@0: nsresult Init(nsIURI *aURI, nsIChannel *aChannel, nsISupports *aContext); michael@0: nsresult Validate(nsIRequest *request, nsISupports *aContext); michael@0: michael@0: // member data michael@0: bool mOnStart; // have we received an OnStart? michael@0: bool mOnStop; // have we received an onStop? michael@0: int32_t mOnDataCount; // number of times OnData was called. michael@0: nsCOMPtr mURI; michael@0: nsCOMPtr mChannel; michael@0: nsCOMPtr mContext; michael@0: }; michael@0: michael@0: // nsISupports implementation michael@0: NS_IMPL_ISUPPORTS(Consumer, nsIStreamListener, nsIRequestObserver) michael@0: michael@0: michael@0: // nsIRequestObserver implementation michael@0: NS_IMETHODIMP michael@0: Consumer::OnStartRequest(nsIRequest *request, nsISupports* aContext) { michael@0: fprintf(stderr, "Consumer::OnStart() -> in\n\n"); michael@0: michael@0: if (mOnStart) { michael@0: fprintf(stderr, "INFO: multiple OnStarts received\n"); michael@0: } michael@0: mOnStart = true; michael@0: michael@0: nsresult rv = Validate(request, aContext); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: fprintf(stderr, "Consumer::OnStart() -> out\n\n"); michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: Consumer::OnStopRequest(nsIRequest *request, nsISupports *aContext, michael@0: nsresult aStatus) { michael@0: fprintf(stderr, "Consumer::OnStop() -> in\n\n"); michael@0: michael@0: if (!mOnStart) { michael@0: gError = true; michael@0: fprintf(stderr, "ERROR: No OnStart received\n"); michael@0: } michael@0: michael@0: if (mOnStop) { michael@0: fprintf(stderr, "INFO: multiple OnStops received\n"); michael@0: } michael@0: michael@0: fprintf(stderr, "INFO: received %d OnData()s\n", mOnDataCount); michael@0: michael@0: mOnStop = true; michael@0: michael@0: nsresult rv = Validate(request, aContext); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: fprintf(stderr, "Consumer::OnStop() -> out\n\n"); michael@0: return rv; michael@0: } michael@0: michael@0: michael@0: // nsIStreamListener implementation michael@0: NS_IMETHODIMP michael@0: Consumer::OnDataAvailable(nsIRequest *request, nsISupports *aContext, michael@0: nsIInputStream *aIStream, michael@0: uint64_t aOffset, uint32_t aLength) { michael@0: fprintf(stderr, "Consumer::OnData() -> in\n\n"); michael@0: michael@0: if (!mOnStart) { michael@0: gError = true; michael@0: fprintf(stderr, "ERROR: No OnStart received\n"); michael@0: } michael@0: michael@0: mOnDataCount += 1; michael@0: michael@0: nsresult rv = Validate(request, aContext); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: fprintf(stderr, "Consumer::OnData() -> out\n\n"); michael@0: return rv; michael@0: } michael@0: michael@0: // Consumer implementation michael@0: Consumer::Consumer() { michael@0: mOnStart = mOnStop = false; michael@0: mOnDataCount = 0; michael@0: gKeepRunning++; michael@0: } michael@0: michael@0: Consumer::~Consumer() { michael@0: fprintf(stderr, "Consumer::~Consumer -> in\n\n"); michael@0: michael@0: if (!mOnStart) { michael@0: gError = true; michael@0: fprintf(stderr, "ERROR: Never got an OnStart\n"); michael@0: } michael@0: michael@0: if (!mOnStop) { michael@0: gError = true; michael@0: fprintf(stderr, "ERROR: Never got an OnStop \n"); michael@0: } michael@0: michael@0: fprintf(stderr, "Consumer::~Consumer -> out\n\n"); michael@0: if (--gKeepRunning == 0) michael@0: QuitPumpingEvents(); michael@0: } michael@0: michael@0: nsresult michael@0: Consumer::Init(nsIURI *aURI, nsIChannel* aChannel, nsISupports *aContext) { michael@0: mURI = aURI; michael@0: mChannel = aChannel; michael@0: mContext = do_QueryInterface(aContext); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: Consumer::Validate(nsIRequest* request, nsISupports *aContext) { michael@0: nsresult rv = NS_OK; michael@0: nsCOMPtr uri; michael@0: nsCOMPtr aChannel = do_QueryInterface(request); michael@0: michael@0: rv = aChannel->GetURI(getter_AddRefs(uri)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: bool same = false; michael@0: michael@0: rv = mURI->Equals(uri, &same); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: if (!same) michael@0: fprintf(stderr, "INFO: URIs do not match\n"); michael@0: michael@0: rv = mContext->Equals((void*)aContext, &same); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: if (!same) { michael@0: gError = true; michael@0: fprintf(stderr, "ERROR: Contexts do not match\n"); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: nsresult StartLoad(const char *); michael@0: michael@0: int main(int argc, char *argv[]) { michael@0: if (test_common_init(&argc, &argv) != 0) michael@0: return -1; michael@0: michael@0: nsresult rv = NS_OK; michael@0: bool cmdLineURL = false; michael@0: michael@0: if (argc > 1) { michael@0: // run in signle url mode michael@0: cmdLineURL = true; michael@0: } michael@0: michael@0: rv = NS_InitXPCOM2(nullptr, nullptr, nullptr); michael@0: if (NS_FAILED(rv)) return -1; michael@0: michael@0: if (cmdLineURL) { michael@0: rv = StartLoad(argv[1]); michael@0: } else { michael@0: rv = StartLoad("http://badhostnamexyz/test.txt"); michael@0: } michael@0: if (NS_FAILED(rv)) return -1; michael@0: michael@0: // Enter the message pump to allow the URL load to proceed. michael@0: PumpEvents(); michael@0: michael@0: NS_ShutdownXPCOM(nullptr); michael@0: if (gError) { michael@0: fprintf(stderr, "\n\n-------ERROR-------\n\n"); michael@0: } michael@0: return 0; michael@0: } michael@0: michael@0: nsresult StartLoad(const char *aURISpec) { michael@0: nsresult rv = NS_OK; michael@0: michael@0: // create a context michael@0: ConsumerContext *context = new ConsumerContext; michael@0: nsCOMPtr contextSup = do_QueryInterface(context, &rv); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: michael@0: nsCOMPtr serv = do_GetService(kIOServiceCID, &rv); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: // create a uri michael@0: nsCOMPtr uri; michael@0: rv = NS_NewURI(getter_AddRefs(uri), aURISpec); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: // create a channel michael@0: nsCOMPtr channel; michael@0: rv = serv->NewChannelFromURI(uri, getter_AddRefs(channel)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: Consumer *consumer = new Consumer; michael@0: rv = consumer->Init(uri, channel, contextSup); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: // kick off the load michael@0: nsCOMPtr request; michael@0: return channel->AsyncOpen(static_cast(consumer), contextSup); michael@0: }