michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=2 sw=2 et cindent: */ 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: /* michael@0: The TestProtocols tests the basic protocols architecture and can michael@0: be used to test individual protocols as well. If this grows too michael@0: big then we should split it to individual protocols. michael@0: michael@0: -Gagan Saksena 04/29/99 michael@0: */ michael@0: michael@0: #include "TestCommon.h" michael@0: #include michael@0: michael@0: #define FORCE_PR_LOG michael@0: #include michael@0: #ifdef WIN32 michael@0: #include michael@0: #endif michael@0: #ifdef XP_UNIX 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 "nsIInputStream.h" michael@0: #include "nsCRT.h" michael@0: #include "nsIChannel.h" michael@0: #include "nsIResumableChannel.h" michael@0: #include "nsIURL.h" michael@0: #include "nsIHttpChannel.h" michael@0: #include "nsIHttpChannelInternal.h" michael@0: #include "nsIHttpHeaderVisitor.h" michael@0: #include "nsIChannelEventSink.h" michael@0: #include "nsIAsyncVerifyRedirectCallback.h" michael@0: #include "nsIInterfaceRequestor.h" michael@0: #include "nsIInterfaceRequestorUtils.h" michael@0: #include "nsIDNSService.h" michael@0: #include "nsIAuthPrompt.h" michael@0: #include "nsIPrefService.h" michael@0: #include "nsIPrefBranch.h" michael@0: #include "nsIPropertyBag2.h" michael@0: #include "nsIWritablePropertyBag2.h" michael@0: #include "nsITimedChannel.h" michael@0: #include "nsChannelProperties.h" michael@0: #include "mozilla/Attributes.h" michael@0: #include "mozilla/unused.h" michael@0: michael@0: #include "nsISimpleEnumerator.h" michael@0: #include "nsStringAPI.h" michael@0: #include "nsNetUtil.h" michael@0: #include "prlog.h" michael@0: michael@0: using namespace mozilla; michael@0: michael@0: namespace TestProtocols { michael@0: michael@0: #if defined(PR_LOGGING) michael@0: // michael@0: // set NSPR_LOG_MODULES=Test:5 michael@0: // michael@0: static PRLogModuleInfo *gTestLog = nullptr; michael@0: #endif michael@0: #define LOG(args) PR_LOG(gTestLog, PR_LOG_DEBUG, args) michael@0: michael@0: static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID); michael@0: michael@0: //static PRTime gElapsedTime; // enable when we time it... michael@0: static int gKeepRunning = 0; michael@0: static bool gVerbose = false; michael@0: static bool gAskUserForInput = false; michael@0: static bool gResume = false; michael@0: static uint64_t gStartAt = 0; michael@0: michael@0: static const char* gEntityID; michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // Set proxy preferences for testing michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: static nsresult michael@0: SetHttpProxy(const char *proxy) michael@0: { michael@0: const char *colon = strchr(proxy, ':'); michael@0: if (!colon) michael@0: { michael@0: NS_WARNING("invalid proxy token; use host:port"); michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: int port = atoi(colon + 1); michael@0: if (port == 0) michael@0: { michael@0: NS_WARNING("invalid proxy port; must be an integer"); michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: nsAutoCString proxyHost; michael@0: proxyHost = Substring(proxy, colon); michael@0: michael@0: nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); michael@0: if (prefs) michael@0: { michael@0: prefs->SetCharPref("network.proxy.http", proxyHost.get()); michael@0: prefs->SetIntPref("network.proxy.http_port", port); michael@0: prefs->SetIntPref("network.proxy.type", 1); // manual proxy config michael@0: } michael@0: LOG(("connecting via proxy=%s:%d\n", proxyHost.get(), port)); michael@0: return NS_OK; michael@0: } michael@0: michael@0: static nsresult michael@0: SetPACFile(const char* pacURL) michael@0: { michael@0: nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); michael@0: if (prefs) michael@0: { michael@0: prefs->SetCharPref("network.proxy.autoconfig_url", pacURL); michael@0: prefs->SetIntPref("network.proxy.type", 2); // PAC file michael@0: } michael@0: LOG(("connecting using PAC file %s\n", pacURL)); michael@0: return NS_OK; michael@0: } michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // Timing information michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: void PrintTimingInformation(nsITimedChannel* channel) { michael@0: #define PRINT_VALUE(property) \ michael@0: { \ michael@0: PRTime value; \ michael@0: channel->Get##property(&value); \ michael@0: if (value) { \ michael@0: PRExplodedTime exploded; \ michael@0: PR_ExplodeTime(value, PR_LocalTimeParameters, &exploded); \ michael@0: char buf[256]; \ michael@0: PR_FormatTime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &exploded); \ michael@0: LOG((" " #property ":\t%s (%i usec)", buf, exploded.tm_usec)); \ michael@0: } else { \ michael@0: LOG((" " #property ":\t0")); \ michael@0: } \ michael@0: } michael@0: LOG(("Timing data:")); michael@0: PRINT_VALUE(ChannelCreationTime) michael@0: PRINT_VALUE(AsyncOpenTime) michael@0: PRINT_VALUE(DomainLookupStartTime) michael@0: PRINT_VALUE(DomainLookupEndTime) michael@0: PRINT_VALUE(ConnectStartTime) michael@0: PRINT_VALUE(ConnectEndTime) michael@0: PRINT_VALUE(RequestStartTime) michael@0: PRINT_VALUE(ResponseStartTime) michael@0: PRINT_VALUE(ResponseEndTime) michael@0: PRINT_VALUE(CacheReadStartTime) michael@0: PRINT_VALUE(CacheReadEndTime) michael@0: } michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // HeaderVisitor michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: class HeaderVisitor : public nsIHttpHeaderVisitor michael@0: { michael@0: public: michael@0: NS_DECL_ISUPPORTS michael@0: NS_DECL_NSIHTTPHEADERVISITOR michael@0: michael@0: HeaderVisitor() { } michael@0: virtual ~HeaderVisitor() {} michael@0: }; michael@0: NS_IMPL_ISUPPORTS(HeaderVisitor, nsIHttpHeaderVisitor) michael@0: michael@0: NS_IMETHODIMP michael@0: HeaderVisitor::VisitHeader(const nsACString &header, const nsACString &value) michael@0: { michael@0: LOG((" %s: %s\n", michael@0: PromiseFlatCString(header).get(), michael@0: PromiseFlatCString(value).get())); michael@0: return NS_OK; michael@0: } michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // URLLoadInfo michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: class URLLoadInfo : public nsISupports michael@0: { michael@0: public: michael@0: michael@0: URLLoadInfo(const char* aUrl); michael@0: virtual ~URLLoadInfo(); michael@0: michael@0: // ISupports interface... michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: michael@0: const char* Name() { return mURLString.get(); } michael@0: int64_t mBytesRead; michael@0: PRTime mTotalTime; michael@0: PRTime mConnectTime; michael@0: nsCString mURLString; michael@0: }; michael@0: michael@0: URLLoadInfo::URLLoadInfo(const char *aUrl) : mURLString(aUrl) michael@0: { michael@0: mBytesRead = 0; michael@0: mConnectTime = mTotalTime = PR_Now(); michael@0: } michael@0: michael@0: URLLoadInfo::~URLLoadInfo() michael@0: { michael@0: } michael@0: michael@0: michael@0: NS_IMPL_ISUPPORTS0(URLLoadInfo) michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // TestChannelEventSink michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: class TestChannelEventSink : public nsIChannelEventSink michael@0: { michael@0: public: michael@0: NS_DECL_ISUPPORTS michael@0: NS_DECL_NSICHANNELEVENTSINK michael@0: michael@0: TestChannelEventSink(); michael@0: virtual ~TestChannelEventSink(); michael@0: }; michael@0: michael@0: TestChannelEventSink::TestChannelEventSink() michael@0: { michael@0: } michael@0: michael@0: TestChannelEventSink::~TestChannelEventSink() michael@0: { michael@0: } michael@0: michael@0: michael@0: NS_IMPL_ISUPPORTS(TestChannelEventSink, nsIChannelEventSink) michael@0: michael@0: NS_IMETHODIMP michael@0: TestChannelEventSink::AsyncOnChannelRedirect(nsIChannel *channel, michael@0: nsIChannel *newChannel, michael@0: uint32_t flags, michael@0: nsIAsyncVerifyRedirectCallback *callback) michael@0: { michael@0: LOG(("\n+++ TestChannelEventSink::OnChannelRedirect (with flags %x) +++\n", michael@0: flags)); michael@0: callback->OnRedirectVerifyCallback(NS_OK); michael@0: return NS_OK; michael@0: } michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // TestAuthPrompt michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: class TestAuthPrompt : public nsIAuthPrompt michael@0: { michael@0: public: michael@0: NS_DECL_ISUPPORTS michael@0: NS_DECL_NSIAUTHPROMPT michael@0: michael@0: TestAuthPrompt(); michael@0: virtual ~TestAuthPrompt(); michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(TestAuthPrompt, nsIAuthPrompt) michael@0: michael@0: TestAuthPrompt::TestAuthPrompt() michael@0: { michael@0: } michael@0: michael@0: TestAuthPrompt::~TestAuthPrompt() michael@0: { michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: TestAuthPrompt::Prompt(const char16_t *dialogTitle, michael@0: const char16_t *text, michael@0: const char16_t *passwordRealm, michael@0: uint32_t savePassword, michael@0: const char16_t *defaultText, michael@0: char16_t **result, michael@0: bool *_retval) michael@0: { michael@0: *_retval = false; michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: TestAuthPrompt::PromptUsernameAndPassword(const char16_t *dialogTitle, michael@0: const char16_t *dialogText, michael@0: const char16_t *passwordRealm, michael@0: uint32_t savePassword, michael@0: char16_t **user, michael@0: char16_t **pwd, michael@0: bool *_retval) michael@0: { michael@0: NS_ConvertUTF16toUTF8 text(passwordRealm); michael@0: printf("* --------------------------------------------------------------------------- *\n"); michael@0: printf("* Authentication Required [%s]\n", text.get()); michael@0: printf("* --------------------------------------------------------------------------- *\n"); michael@0: michael@0: char buf[256]; michael@0: int n; michael@0: michael@0: printf("Enter username: "); michael@0: unused << fgets(buf, sizeof(buf), stdin); michael@0: n = strlen(buf); michael@0: buf[n-1] = '\0'; // trim trailing newline michael@0: *user = NS_StringCloneData(NS_ConvertUTF8toUTF16(buf)); michael@0: michael@0: const char *p; michael@0: #if defined(XP_UNIX) && !defined(ANDROID) michael@0: p = getpass("Enter password: "); michael@0: #else michael@0: printf("Enter password: "); michael@0: fgets(buf, sizeof(buf), stdin); michael@0: n = strlen(buf); michael@0: buf[n-1] = '\0'; // trim trailing newline michael@0: p = buf; michael@0: #endif michael@0: *pwd = NS_StringCloneData(NS_ConvertUTF8toUTF16(p)); michael@0: michael@0: // zap buf michael@0: memset(buf, 0, sizeof(buf)); michael@0: michael@0: *_retval = true; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: TestAuthPrompt::PromptPassword(const char16_t *dialogTitle, michael@0: const char16_t *text, michael@0: const char16_t *passwordRealm, michael@0: uint32_t savePassword, michael@0: char16_t **pwd, michael@0: bool *_retval) michael@0: { michael@0: *_retval = false; michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // InputTestConsumer michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: class InputTestConsumer : public nsIStreamListener michael@0: { michael@0: public: michael@0: michael@0: InputTestConsumer(); michael@0: virtual ~InputTestConsumer(); michael@0: michael@0: NS_DECL_ISUPPORTS michael@0: NS_DECL_NSIREQUESTOBSERVER michael@0: NS_DECL_NSISTREAMLISTENER michael@0: }; michael@0: michael@0: InputTestConsumer::InputTestConsumer() michael@0: { michael@0: } michael@0: michael@0: InputTestConsumer::~InputTestConsumer() michael@0: { michael@0: } michael@0: michael@0: NS_IMPL_ISUPPORTS(InputTestConsumer, nsIStreamListener, nsIRequestObserver) michael@0: michael@0: NS_IMETHODIMP michael@0: InputTestConsumer::OnStartRequest(nsIRequest *request, nsISupports* context) michael@0: { michael@0: LOG(("InputTestConsumer::OnStartRequest\n")); michael@0: michael@0: URLLoadInfo* info = (URLLoadInfo*)context; michael@0: if (info) michael@0: info->mConnectTime = PR_Now() - info->mConnectTime; michael@0: michael@0: if (gVerbose) { michael@0: LOG(("\nStarted loading: %s\n", info ? info->Name() : "UNKNOWN URL")); michael@0: } michael@0: michael@0: nsAutoCString value; michael@0: michael@0: nsCOMPtr channel = do_QueryInterface(request); michael@0: if (channel) { michael@0: nsresult status; michael@0: channel->GetStatus(&status); michael@0: LOG(("Channel Status: %08x\n", status)); michael@0: if (NS_SUCCEEDED(status)) { michael@0: LOG(("Channel Info:\n")); michael@0: michael@0: channel->GetName(value); michael@0: LOG(("\tName: %s\n", value.get())); michael@0: michael@0: channel->GetContentType(value); michael@0: LOG(("\tContent-Type: %s\n", value.get())); michael@0: michael@0: channel->GetContentCharset(value); michael@0: LOG(("\tContent-Charset: %s\n", value.get())); michael@0: michael@0: int64_t length = -1; michael@0: if (NS_SUCCEEDED(channel->GetContentLength(&length))) { michael@0: LOG(("\tContent-Length: %lld\n", length)); michael@0: } else { michael@0: LOG(("\tContent-Length: Unknown\n")); michael@0: } michael@0: } michael@0: michael@0: nsCOMPtr owner; michael@0: channel->GetOwner(getter_AddRefs(owner)); michael@0: LOG(("\tChannel Owner: %x\n", owner.get())); michael@0: } michael@0: michael@0: nsCOMPtr props = do_QueryInterface(request); michael@0: if (props) { michael@0: nsCOMPtr foo; michael@0: props->GetPropertyAsInterface(NS_LITERAL_STRING("test.foo"), michael@0: NS_GET_IID(nsIURI), michael@0: getter_AddRefs(foo)); michael@0: if (foo) { michael@0: nsAutoCString spec; michael@0: foo->GetSpec(spec); michael@0: LOG(("\ttest.foo: %s\n", spec.get())); michael@0: } michael@0: } michael@0: michael@0: nsCOMPtr httpChannelInt(do_QueryInterface(request)); michael@0: if (httpChannelInt) { michael@0: uint32_t majorVer, minorVer; michael@0: nsresult rv = httpChannelInt->GetResponseVersion(&majorVer, &minorVer); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: LOG(("HTTP Response version: %u.%u\n", majorVer, minorVer)); michael@0: } michael@0: } michael@0: nsCOMPtr httpChannel(do_QueryInterface(request)); michael@0: if (httpChannel) { michael@0: HeaderVisitor *visitor = new HeaderVisitor(); michael@0: if (!visitor) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: NS_ADDREF(visitor); michael@0: michael@0: LOG(("HTTP request headers:\n")); michael@0: httpChannel->VisitRequestHeaders(visitor); michael@0: michael@0: LOG(("HTTP response headers:\n")); michael@0: httpChannel->VisitResponseHeaders(visitor); michael@0: michael@0: NS_RELEASE(visitor); michael@0: } michael@0: michael@0: nsCOMPtr resChannel = do_QueryInterface(request); michael@0: if (resChannel) { michael@0: LOG(("Resumable entity identification:\n")); michael@0: nsAutoCString entityID; michael@0: nsresult rv = resChannel->GetEntityID(entityID); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: LOG(("\t|%s|\n", entityID.get())); michael@0: } michael@0: else { michael@0: LOG(("\t\n")); michael@0: } michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: InputTestConsumer::OnDataAvailable(nsIRequest *request, michael@0: nsISupports* context, michael@0: nsIInputStream *aIStream, michael@0: uint64_t aSourceOffset, michael@0: uint32_t aLength) michael@0: { michael@0: char buf[1025]; michael@0: uint32_t amt, size; michael@0: nsresult rv; michael@0: URLLoadInfo* info = (URLLoadInfo*)context; michael@0: michael@0: while (aLength) { michael@0: size = std::min(aLength, sizeof(buf)); michael@0: michael@0: rv = aIStream->Read(buf, size, &amt); michael@0: if (NS_FAILED(rv)) { michael@0: NS_ASSERTION((NS_BASE_STREAM_WOULD_BLOCK != rv), michael@0: "The stream should never block."); michael@0: return rv; michael@0: } michael@0: if (gVerbose) { michael@0: buf[amt] = '\0'; michael@0: puts(buf); michael@0: } michael@0: if (info) { michael@0: info->mBytesRead += amt; michael@0: } michael@0: michael@0: aLength -= amt; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: InputTestConsumer::OnStopRequest(nsIRequest *request, nsISupports* context, michael@0: nsresult aStatus) michael@0: { michael@0: LOG(("InputTestConsumer::OnStopRequest [status=%x]\n", aStatus)); michael@0: michael@0: URLLoadInfo* info = (URLLoadInfo*)context; michael@0: michael@0: if (info) { michael@0: uint32_t httpStatus; michael@0: bool bHTTPURL = false; michael@0: michael@0: info->mTotalTime = PR_Now() - info->mTotalTime; michael@0: michael@0: double readTime = ((info->mTotalTime-info->mConnectTime)/1000.0)/1000.0; michael@0: michael@0: nsCOMPtr pHTTPCon(do_QueryInterface(request)); michael@0: if (pHTTPCon) { michael@0: pHTTPCon->GetResponseStatus(&httpStatus); michael@0: bHTTPURL = true; michael@0: } michael@0: michael@0: LOG(("\nFinished loading: %s Status Code: %x\n", info->Name(), aStatus)); michael@0: if (bHTTPURL) { michael@0: LOG(("\tHTTP Status: %u\n", httpStatus)); michael@0: } michael@0: if (NS_ERROR_UNKNOWN_HOST == aStatus || michael@0: NS_ERROR_UNKNOWN_PROXY_HOST == aStatus) { michael@0: LOG(("\tDNS lookup failed.\n")); michael@0: } michael@0: LOG(("\tTime to connect: %.3f seconds\n", (info->mConnectTime/1000.0)/1000.0)); michael@0: LOG(("\tTime to read: %.3f seconds.\n", readTime)); michael@0: LOG(("\tRead: %lld bytes.\n", info->mBytesRead)); michael@0: if (info->mBytesRead == int64_t(0)) { michael@0: } else if (readTime > 0.0) { michael@0: LOG(("\tThroughput: %.0f bps.\n", (double)(info->mBytesRead*int64_t(8))/readTime)); michael@0: } else { michael@0: LOG(("\tThroughput: REAL FAST!!\n")); michael@0: } michael@0: michael@0: nsCOMPtr timed(do_QueryInterface(request)); michael@0: if (timed) michael@0: PrintTimingInformation(timed); michael@0: } else { michael@0: LOG(("\nFinished loading: UNKNOWN URL. Status Code: %x\n", aStatus)); michael@0: } michael@0: michael@0: if (--gKeepRunning == 0) michael@0: QuitPumpingEvents(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // NotificationCallbacks michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: class NotificationCallbacks MOZ_FINAL : public nsIInterfaceRequestor { michael@0: public: michael@0: NS_DECL_ISUPPORTS michael@0: michael@0: NotificationCallbacks() { michael@0: } michael@0: michael@0: NS_IMETHOD GetInterface(const nsIID& iid, void* *result) { michael@0: nsresult rv = NS_ERROR_FAILURE; michael@0: michael@0: if (iid.Equals(NS_GET_IID(nsIChannelEventSink))) { michael@0: TestChannelEventSink *sink; michael@0: michael@0: sink = new TestChannelEventSink(); michael@0: if (sink == nullptr) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: NS_ADDREF(sink); michael@0: rv = sink->QueryInterface(iid, result); michael@0: NS_RELEASE(sink); michael@0: } michael@0: michael@0: if (iid.Equals(NS_GET_IID(nsIAuthPrompt))) { michael@0: TestAuthPrompt *prompt; michael@0: michael@0: prompt = new TestAuthPrompt(); michael@0: if (prompt == nullptr) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: NS_ADDREF(prompt); michael@0: rv = prompt->QueryInterface(iid, result); michael@0: NS_RELEASE(prompt); michael@0: } michael@0: return rv; michael@0: } michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(NotificationCallbacks, nsIInterfaceRequestor) michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // helpers... michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: nsresult StartLoadingURL(const char* aUrlString) michael@0: { michael@0: nsresult rv; michael@0: michael@0: nsCOMPtr pService(do_GetService(kIOServiceCID, &rv)); michael@0: if (pService) { michael@0: nsCOMPtr pURL; michael@0: michael@0: rv = pService->NewURI(nsDependentCString(aUrlString), nullptr, nullptr, getter_AddRefs(pURL)); michael@0: if (NS_FAILED(rv)) { michael@0: LOG(("ERROR: NewURI failed for %s [rv=%x]\n", aUrlString)); michael@0: return rv; michael@0: } michael@0: nsCOMPtr pChannel; michael@0: michael@0: NotificationCallbacks* callbacks = new NotificationCallbacks(); michael@0: if (!callbacks) { michael@0: LOG(("Failed to create a new consumer!")); michael@0: return NS_ERROR_OUT_OF_MEMORY;; michael@0: } michael@0: NS_ADDREF(callbacks); michael@0: michael@0: // Async reading thru the calls of the event sink interface michael@0: rv = NS_NewChannel(getter_AddRefs(pChannel), pURL, pService, michael@0: nullptr, // loadGroup michael@0: callbacks); // notificationCallbacks michael@0: NS_RELEASE(callbacks); michael@0: if (NS_FAILED(rv)) { michael@0: LOG(("ERROR: NS_OpenURI failed for %s [rv=%x]\n", aUrlString, rv)); michael@0: return rv; michael@0: } michael@0: michael@0: nsCOMPtr timed(do_QueryInterface(pChannel)); michael@0: if (timed) michael@0: timed->SetTimingEnabled(true); michael@0: michael@0: nsCOMPtr props = do_QueryInterface(pChannel); michael@0: if (props) { michael@0: rv = props->SetPropertyAsInterface(NS_LITERAL_STRING("test.foo"), michael@0: pURL); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: LOG(("set prop 'test.foo'\n")); michael@0: } michael@0: } michael@0: michael@0: /* michael@0: You may optionally add/set other headers on this michael@0: request object. This is done by QI for the specific michael@0: protocolConnection. michael@0: */ michael@0: nsCOMPtr pHTTPCon(do_QueryInterface(pChannel)); michael@0: michael@0: if (pHTTPCon) { michael@0: // Setting a sample header. michael@0: rv = pHTTPCon->SetRequestHeader(NS_LITERAL_CSTRING("sample-header"), michael@0: NS_LITERAL_CSTRING("Sample-Value"), michael@0: false); michael@0: if (NS_FAILED(rv)) return rv; michael@0: } michael@0: InputTestConsumer* listener; michael@0: michael@0: listener = new InputTestConsumer; michael@0: NS_IF_ADDREF(listener); michael@0: if (!listener) { michael@0: NS_ERROR("Failed to create a new stream listener!"); michael@0: return NS_ERROR_OUT_OF_MEMORY;; michael@0: } michael@0: michael@0: URLLoadInfo* info; michael@0: info = new URLLoadInfo(aUrlString); michael@0: NS_IF_ADDREF(info); michael@0: if (!info) { michael@0: NS_ERROR("Failed to create a load info!"); michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: michael@0: if (gResume) { michael@0: nsCOMPtr res = do_QueryInterface(pChannel); michael@0: if (!res) { michael@0: NS_ERROR("Channel is not resumable!"); michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: nsAutoCString id; michael@0: if (gEntityID) michael@0: id = gEntityID; michael@0: LOG(("* resuming at %llu bytes, with entity id |%s|\n", gStartAt, id.get())); michael@0: res->ResumeAt(gStartAt, id); michael@0: } michael@0: rv = pChannel->AsyncOpen(listener, // IStreamListener consumer michael@0: info); michael@0: michael@0: if (NS_SUCCEEDED(rv)) { michael@0: gKeepRunning++; michael@0: } michael@0: else { michael@0: LOG(("ERROR: AsyncOpen failed [rv=%x]\n", rv)); michael@0: } michael@0: NS_RELEASE(listener); michael@0: NS_RELEASE(info); michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: static int32_t michael@0: FindChar(nsCString& buffer, char c) michael@0: { michael@0: const char *b; michael@0: int32_t len = NS_CStringGetData(buffer, &b); michael@0: michael@0: for (int32_t offset = 0; offset < len; ++offset) { michael@0: if (b[offset] == c) michael@0: return offset; michael@0: } michael@0: michael@0: return -1; michael@0: } michael@0: michael@0: michael@0: static void michael@0: StripChar(nsCString& buffer, char c) michael@0: { michael@0: const char *b; michael@0: uint32_t len = NS_CStringGetData(buffer, &b) - 1; michael@0: michael@0: for (; len > 0; --len) { michael@0: if (b[len] == c) { michael@0: buffer.Cut(len, 1); michael@0: NS_CStringGetData(buffer, &b); michael@0: } michael@0: } michael@0: } michael@0: michael@0: nsresult LoadURLsFromFile(char *aFileName) michael@0: { michael@0: nsresult rv = NS_OK; michael@0: int32_t len, offset; michael@0: PRFileDesc* fd; michael@0: char buffer[1024]; michael@0: nsCString fileBuffer; michael@0: nsCString urlString; michael@0: michael@0: fd = PR_Open(aFileName, PR_RDONLY, 777); michael@0: if (!fd) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: // Keep reading the file until EOF (or an error) is reached... michael@0: do { michael@0: len = PR_Read(fd, buffer, sizeof(buffer)); michael@0: if (len>0) { michael@0: fileBuffer.Append(buffer, len); michael@0: // Treat each line as a URL... michael@0: while ((offset = FindChar(fileBuffer, '\n')) != -1) { michael@0: urlString = StringHead(fileBuffer, offset); michael@0: fileBuffer.Cut(0, offset+1); michael@0: michael@0: StripChar(urlString, '\r'); michael@0: if (urlString.Length()) { michael@0: LOG(("\t%s\n", urlString.get())); michael@0: rv = StartLoadingURL(urlString.get()); michael@0: if (NS_FAILED(rv)) { michael@0: // No need to log an error -- StartLoadingURL already michael@0: // did that for us, probably. michael@0: PR_Close(fd); michael@0: return rv; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } while (len>0); michael@0: michael@0: // If anything is left in the fileBuffer, treat it as a URL... michael@0: StripChar(fileBuffer, '\r'); michael@0: if (fileBuffer.Length()) { michael@0: LOG(("\t%s\n", fileBuffer.get())); michael@0: StartLoadingURL(fileBuffer.get()); michael@0: } michael@0: michael@0: PR_Close(fd); michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: nsresult LoadURLFromConsole() michael@0: { michael@0: char buffer[1024]; michael@0: printf("Enter URL (\"q\" to start): "); michael@0: unused << scanf("%s", buffer); michael@0: if (buffer[0]=='q') michael@0: gAskUserForInput = false; michael@0: else michael@0: StartLoadingURL(buffer); michael@0: return NS_OK; michael@0: } michael@0: michael@0: } // namespace michael@0: michael@0: using namespace TestProtocols; michael@0: michael@0: int michael@0: main(int argc, char* argv[]) michael@0: { michael@0: if (test_common_init(&argc, &argv) != 0) michael@0: return -1; michael@0: michael@0: nsresult rv= (nsresult)-1; michael@0: if (argc < 2) { michael@0: printf("usage: %s [-verbose] [-file ] [-resume " michael@0: "[-entityid ]] [-proxy ] [-pac ]" michael@0: "[-console] ... \n", argv[0]); michael@0: return -1; michael@0: } michael@0: michael@0: #if defined(PR_LOGGING) michael@0: gTestLog = PR_NewLogModule("Test"); michael@0: #endif michael@0: michael@0: /* michael@0: The following code only deals with XPCOM registration stuff. and setting michael@0: up the event queues. Copied from TestSocketIO.cpp michael@0: */ michael@0: michael@0: rv = NS_InitXPCOM2(nullptr, nullptr, nullptr); michael@0: if (NS_FAILED(rv)) return -1; michael@0: michael@0: { michael@0: int i; michael@0: LOG(("Trying to load:\n")); michael@0: for (i=1; i