Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 sw=2 et cindent: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /*
8 The TestProtocols tests the basic protocols architecture and can
9 be used to test individual protocols as well. If this grows too
10 big then we should split it to individual protocols.
12 -Gagan Saksena 04/29/99
13 */
15 #include "TestCommon.h"
16 #include <algorithm>
18 #define FORCE_PR_LOG
19 #include <stdio.h>
20 #ifdef WIN32
21 #include <windows.h>
22 #endif
23 #ifdef XP_UNIX
24 #include <unistd.h>
25 #endif
26 #include "nspr.h"
27 #include "nscore.h"
28 #include "nsCOMPtr.h"
29 #include "nsIIOService.h"
30 #include "nsIServiceManager.h"
31 #include "nsIStreamListener.h"
32 #include "nsIInputStream.h"
33 #include "nsIInputStream.h"
34 #include "nsCRT.h"
35 #include "nsIChannel.h"
36 #include "nsIResumableChannel.h"
37 #include "nsIURL.h"
38 #include "nsIHttpChannel.h"
39 #include "nsIHttpChannelInternal.h"
40 #include "nsIHttpHeaderVisitor.h"
41 #include "nsIChannelEventSink.h"
42 #include "nsIAsyncVerifyRedirectCallback.h"
43 #include "nsIInterfaceRequestor.h"
44 #include "nsIInterfaceRequestorUtils.h"
45 #include "nsIDNSService.h"
46 #include "nsIAuthPrompt.h"
47 #include "nsIPrefService.h"
48 #include "nsIPrefBranch.h"
49 #include "nsIPropertyBag2.h"
50 #include "nsIWritablePropertyBag2.h"
51 #include "nsITimedChannel.h"
52 #include "nsChannelProperties.h"
53 #include "mozilla/Attributes.h"
54 #include "mozilla/unused.h"
56 #include "nsISimpleEnumerator.h"
57 #include "nsStringAPI.h"
58 #include "nsNetUtil.h"
59 #include "prlog.h"
61 using namespace mozilla;
63 namespace TestProtocols {
65 #if defined(PR_LOGGING)
66 //
67 // set NSPR_LOG_MODULES=Test:5
68 //
69 static PRLogModuleInfo *gTestLog = nullptr;
70 #endif
71 #define LOG(args) PR_LOG(gTestLog, PR_LOG_DEBUG, args)
73 static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
75 //static PRTime gElapsedTime; // enable when we time it...
76 static int gKeepRunning = 0;
77 static bool gVerbose = false;
78 static bool gAskUserForInput = false;
79 static bool gResume = false;
80 static uint64_t gStartAt = 0;
82 static const char* gEntityID;
84 //-----------------------------------------------------------------------------
85 // Set proxy preferences for testing
86 //-----------------------------------------------------------------------------
88 static nsresult
89 SetHttpProxy(const char *proxy)
90 {
91 const char *colon = strchr(proxy, ':');
92 if (!colon)
93 {
94 NS_WARNING("invalid proxy token; use host:port");
95 return NS_ERROR_UNEXPECTED;
96 }
97 int port = atoi(colon + 1);
98 if (port == 0)
99 {
100 NS_WARNING("invalid proxy port; must be an integer");
101 return NS_ERROR_UNEXPECTED;
102 }
103 nsAutoCString proxyHost;
104 proxyHost = Substring(proxy, colon);
106 nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
107 if (prefs)
108 {
109 prefs->SetCharPref("network.proxy.http", proxyHost.get());
110 prefs->SetIntPref("network.proxy.http_port", port);
111 prefs->SetIntPref("network.proxy.type", 1); // manual proxy config
112 }
113 LOG(("connecting via proxy=%s:%d\n", proxyHost.get(), port));
114 return NS_OK;
115 }
117 static nsresult
118 SetPACFile(const char* pacURL)
119 {
120 nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
121 if (prefs)
122 {
123 prefs->SetCharPref("network.proxy.autoconfig_url", pacURL);
124 prefs->SetIntPref("network.proxy.type", 2); // PAC file
125 }
126 LOG(("connecting using PAC file %s\n", pacURL));
127 return NS_OK;
128 }
130 //-----------------------------------------------------------------------------
131 // Timing information
132 //-----------------------------------------------------------------------------
134 void PrintTimingInformation(nsITimedChannel* channel) {
135 #define PRINT_VALUE(property) \
136 { \
137 PRTime value; \
138 channel->Get##property(&value); \
139 if (value) { \
140 PRExplodedTime exploded; \
141 PR_ExplodeTime(value, PR_LocalTimeParameters, &exploded); \
142 char buf[256]; \
143 PR_FormatTime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &exploded); \
144 LOG((" " #property ":\t%s (%i usec)", buf, exploded.tm_usec)); \
145 } else { \
146 LOG((" " #property ":\t0")); \
147 } \
148 }
149 LOG(("Timing data:"));
150 PRINT_VALUE(ChannelCreationTime)
151 PRINT_VALUE(AsyncOpenTime)
152 PRINT_VALUE(DomainLookupStartTime)
153 PRINT_VALUE(DomainLookupEndTime)
154 PRINT_VALUE(ConnectStartTime)
155 PRINT_VALUE(ConnectEndTime)
156 PRINT_VALUE(RequestStartTime)
157 PRINT_VALUE(ResponseStartTime)
158 PRINT_VALUE(ResponseEndTime)
159 PRINT_VALUE(CacheReadStartTime)
160 PRINT_VALUE(CacheReadEndTime)
161 }
163 //-----------------------------------------------------------------------------
164 // HeaderVisitor
165 //-----------------------------------------------------------------------------
167 class HeaderVisitor : public nsIHttpHeaderVisitor
168 {
169 public:
170 NS_DECL_ISUPPORTS
171 NS_DECL_NSIHTTPHEADERVISITOR
173 HeaderVisitor() { }
174 virtual ~HeaderVisitor() {}
175 };
176 NS_IMPL_ISUPPORTS(HeaderVisitor, nsIHttpHeaderVisitor)
178 NS_IMETHODIMP
179 HeaderVisitor::VisitHeader(const nsACString &header, const nsACString &value)
180 {
181 LOG((" %s: %s\n",
182 PromiseFlatCString(header).get(),
183 PromiseFlatCString(value).get()));
184 return NS_OK;
185 }
187 //-----------------------------------------------------------------------------
188 // URLLoadInfo
189 //-----------------------------------------------------------------------------
191 class URLLoadInfo : public nsISupports
192 {
193 public:
195 URLLoadInfo(const char* aUrl);
196 virtual ~URLLoadInfo();
198 // ISupports interface...
199 NS_DECL_THREADSAFE_ISUPPORTS
201 const char* Name() { return mURLString.get(); }
202 int64_t mBytesRead;
203 PRTime mTotalTime;
204 PRTime mConnectTime;
205 nsCString mURLString;
206 };
208 URLLoadInfo::URLLoadInfo(const char *aUrl) : mURLString(aUrl)
209 {
210 mBytesRead = 0;
211 mConnectTime = mTotalTime = PR_Now();
212 }
214 URLLoadInfo::~URLLoadInfo()
215 {
216 }
219 NS_IMPL_ISUPPORTS0(URLLoadInfo)
221 //-----------------------------------------------------------------------------
222 // TestChannelEventSink
223 //-----------------------------------------------------------------------------
225 class TestChannelEventSink : public nsIChannelEventSink
226 {
227 public:
228 NS_DECL_ISUPPORTS
229 NS_DECL_NSICHANNELEVENTSINK
231 TestChannelEventSink();
232 virtual ~TestChannelEventSink();
233 };
235 TestChannelEventSink::TestChannelEventSink()
236 {
237 }
239 TestChannelEventSink::~TestChannelEventSink()
240 {
241 }
244 NS_IMPL_ISUPPORTS(TestChannelEventSink, nsIChannelEventSink)
246 NS_IMETHODIMP
247 TestChannelEventSink::AsyncOnChannelRedirect(nsIChannel *channel,
248 nsIChannel *newChannel,
249 uint32_t flags,
250 nsIAsyncVerifyRedirectCallback *callback)
251 {
252 LOG(("\n+++ TestChannelEventSink::OnChannelRedirect (with flags %x) +++\n",
253 flags));
254 callback->OnRedirectVerifyCallback(NS_OK);
255 return NS_OK;
256 }
258 //-----------------------------------------------------------------------------
259 // TestAuthPrompt
260 //-----------------------------------------------------------------------------
262 class TestAuthPrompt : public nsIAuthPrompt
263 {
264 public:
265 NS_DECL_ISUPPORTS
266 NS_DECL_NSIAUTHPROMPT
268 TestAuthPrompt();
269 virtual ~TestAuthPrompt();
270 };
272 NS_IMPL_ISUPPORTS(TestAuthPrompt, nsIAuthPrompt)
274 TestAuthPrompt::TestAuthPrompt()
275 {
276 }
278 TestAuthPrompt::~TestAuthPrompt()
279 {
280 }
282 NS_IMETHODIMP
283 TestAuthPrompt::Prompt(const char16_t *dialogTitle,
284 const char16_t *text,
285 const char16_t *passwordRealm,
286 uint32_t savePassword,
287 const char16_t *defaultText,
288 char16_t **result,
289 bool *_retval)
290 {
291 *_retval = false;
292 return NS_ERROR_NOT_IMPLEMENTED;
293 }
295 NS_IMETHODIMP
296 TestAuthPrompt::PromptUsernameAndPassword(const char16_t *dialogTitle,
297 const char16_t *dialogText,
298 const char16_t *passwordRealm,
299 uint32_t savePassword,
300 char16_t **user,
301 char16_t **pwd,
302 bool *_retval)
303 {
304 NS_ConvertUTF16toUTF8 text(passwordRealm);
305 printf("* --------------------------------------------------------------------------- *\n");
306 printf("* Authentication Required [%s]\n", text.get());
307 printf("* --------------------------------------------------------------------------- *\n");
309 char buf[256];
310 int n;
312 printf("Enter username: ");
313 unused << fgets(buf, sizeof(buf), stdin);
314 n = strlen(buf);
315 buf[n-1] = '\0'; // trim trailing newline
316 *user = NS_StringCloneData(NS_ConvertUTF8toUTF16(buf));
318 const char *p;
319 #if defined(XP_UNIX) && !defined(ANDROID)
320 p = getpass("Enter password: ");
321 #else
322 printf("Enter password: ");
323 fgets(buf, sizeof(buf), stdin);
324 n = strlen(buf);
325 buf[n-1] = '\0'; // trim trailing newline
326 p = buf;
327 #endif
328 *pwd = NS_StringCloneData(NS_ConvertUTF8toUTF16(p));
330 // zap buf
331 memset(buf, 0, sizeof(buf));
333 *_retval = true;
334 return NS_OK;
335 }
337 NS_IMETHODIMP
338 TestAuthPrompt::PromptPassword(const char16_t *dialogTitle,
339 const char16_t *text,
340 const char16_t *passwordRealm,
341 uint32_t savePassword,
342 char16_t **pwd,
343 bool *_retval)
344 {
345 *_retval = false;
346 return NS_ERROR_NOT_IMPLEMENTED;
347 }
349 //-----------------------------------------------------------------------------
350 // InputTestConsumer
351 //-----------------------------------------------------------------------------
353 class InputTestConsumer : public nsIStreamListener
354 {
355 public:
357 InputTestConsumer();
358 virtual ~InputTestConsumer();
360 NS_DECL_ISUPPORTS
361 NS_DECL_NSIREQUESTOBSERVER
362 NS_DECL_NSISTREAMLISTENER
363 };
365 InputTestConsumer::InputTestConsumer()
366 {
367 }
369 InputTestConsumer::~InputTestConsumer()
370 {
371 }
373 NS_IMPL_ISUPPORTS(InputTestConsumer, nsIStreamListener, nsIRequestObserver)
375 NS_IMETHODIMP
376 InputTestConsumer::OnStartRequest(nsIRequest *request, nsISupports* context)
377 {
378 LOG(("InputTestConsumer::OnStartRequest\n"));
380 URLLoadInfo* info = (URLLoadInfo*)context;
381 if (info)
382 info->mConnectTime = PR_Now() - info->mConnectTime;
384 if (gVerbose) {
385 LOG(("\nStarted loading: %s\n", info ? info->Name() : "UNKNOWN URL"));
386 }
388 nsAutoCString value;
390 nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
391 if (channel) {
392 nsresult status;
393 channel->GetStatus(&status);
394 LOG(("Channel Status: %08x\n", status));
395 if (NS_SUCCEEDED(status)) {
396 LOG(("Channel Info:\n"));
398 channel->GetName(value);
399 LOG(("\tName: %s\n", value.get()));
401 channel->GetContentType(value);
402 LOG(("\tContent-Type: %s\n", value.get()));
404 channel->GetContentCharset(value);
405 LOG(("\tContent-Charset: %s\n", value.get()));
407 int64_t length = -1;
408 if (NS_SUCCEEDED(channel->GetContentLength(&length))) {
409 LOG(("\tContent-Length: %lld\n", length));
410 } else {
411 LOG(("\tContent-Length: Unknown\n"));
412 }
413 }
415 nsCOMPtr<nsISupports> owner;
416 channel->GetOwner(getter_AddRefs(owner));
417 LOG(("\tChannel Owner: %x\n", owner.get()));
418 }
420 nsCOMPtr<nsIPropertyBag2> props = do_QueryInterface(request);
421 if (props) {
422 nsCOMPtr<nsIURI> foo;
423 props->GetPropertyAsInterface(NS_LITERAL_STRING("test.foo"),
424 NS_GET_IID(nsIURI),
425 getter_AddRefs(foo));
426 if (foo) {
427 nsAutoCString spec;
428 foo->GetSpec(spec);
429 LOG(("\ttest.foo: %s\n", spec.get()));
430 }
431 }
433 nsCOMPtr<nsIHttpChannelInternal> httpChannelInt(do_QueryInterface(request));
434 if (httpChannelInt) {
435 uint32_t majorVer, minorVer;
436 nsresult rv = httpChannelInt->GetResponseVersion(&majorVer, &minorVer);
437 if (NS_SUCCEEDED(rv)) {
438 LOG(("HTTP Response version: %u.%u\n", majorVer, minorVer));
439 }
440 }
441 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(request));
442 if (httpChannel) {
443 HeaderVisitor *visitor = new HeaderVisitor();
444 if (!visitor)
445 return NS_ERROR_OUT_OF_MEMORY;
446 NS_ADDREF(visitor);
448 LOG(("HTTP request headers:\n"));
449 httpChannel->VisitRequestHeaders(visitor);
451 LOG(("HTTP response headers:\n"));
452 httpChannel->VisitResponseHeaders(visitor);
454 NS_RELEASE(visitor);
455 }
457 nsCOMPtr<nsIResumableChannel> resChannel = do_QueryInterface(request);
458 if (resChannel) {
459 LOG(("Resumable entity identification:\n"));
460 nsAutoCString entityID;
461 nsresult rv = resChannel->GetEntityID(entityID);
462 if (NS_SUCCEEDED(rv)) {
463 LOG(("\t|%s|\n", entityID.get()));
464 }
465 else {
466 LOG(("\t<none>\n"));
467 }
468 }
470 return NS_OK;
471 }
473 NS_IMETHODIMP
474 InputTestConsumer::OnDataAvailable(nsIRequest *request,
475 nsISupports* context,
476 nsIInputStream *aIStream,
477 uint64_t aSourceOffset,
478 uint32_t aLength)
479 {
480 char buf[1025];
481 uint32_t amt, size;
482 nsresult rv;
483 URLLoadInfo* info = (URLLoadInfo*)context;
485 while (aLength) {
486 size = std::min<uint32_t>(aLength, sizeof(buf));
488 rv = aIStream->Read(buf, size, &amt);
489 if (NS_FAILED(rv)) {
490 NS_ASSERTION((NS_BASE_STREAM_WOULD_BLOCK != rv),
491 "The stream should never block.");
492 return rv;
493 }
494 if (gVerbose) {
495 buf[amt] = '\0';
496 puts(buf);
497 }
498 if (info) {
499 info->mBytesRead += amt;
500 }
502 aLength -= amt;
503 }
504 return NS_OK;
505 }
507 NS_IMETHODIMP
508 InputTestConsumer::OnStopRequest(nsIRequest *request, nsISupports* context,
509 nsresult aStatus)
510 {
511 LOG(("InputTestConsumer::OnStopRequest [status=%x]\n", aStatus));
513 URLLoadInfo* info = (URLLoadInfo*)context;
515 if (info) {
516 uint32_t httpStatus;
517 bool bHTTPURL = false;
519 info->mTotalTime = PR_Now() - info->mTotalTime;
521 double readTime = ((info->mTotalTime-info->mConnectTime)/1000.0)/1000.0;
523 nsCOMPtr<nsIHttpChannel> pHTTPCon(do_QueryInterface(request));
524 if (pHTTPCon) {
525 pHTTPCon->GetResponseStatus(&httpStatus);
526 bHTTPURL = true;
527 }
529 LOG(("\nFinished loading: %s Status Code: %x\n", info->Name(), aStatus));
530 if (bHTTPURL) {
531 LOG(("\tHTTP Status: %u\n", httpStatus));
532 }
533 if (NS_ERROR_UNKNOWN_HOST == aStatus ||
534 NS_ERROR_UNKNOWN_PROXY_HOST == aStatus) {
535 LOG(("\tDNS lookup failed.\n"));
536 }
537 LOG(("\tTime to connect: %.3f seconds\n", (info->mConnectTime/1000.0)/1000.0));
538 LOG(("\tTime to read: %.3f seconds.\n", readTime));
539 LOG(("\tRead: %lld bytes.\n", info->mBytesRead));
540 if (info->mBytesRead == int64_t(0)) {
541 } else if (readTime > 0.0) {
542 LOG(("\tThroughput: %.0f bps.\n", (double)(info->mBytesRead*int64_t(8))/readTime));
543 } else {
544 LOG(("\tThroughput: REAL FAST!!\n"));
545 }
547 nsCOMPtr<nsITimedChannel> timed(do_QueryInterface(request));
548 if (timed)
549 PrintTimingInformation(timed);
550 } else {
551 LOG(("\nFinished loading: UNKNOWN URL. Status Code: %x\n", aStatus));
552 }
554 if (--gKeepRunning == 0)
555 QuitPumpingEvents();
556 return NS_OK;
557 }
559 //-----------------------------------------------------------------------------
560 // NotificationCallbacks
561 //-----------------------------------------------------------------------------
563 class NotificationCallbacks MOZ_FINAL : public nsIInterfaceRequestor {
564 public:
565 NS_DECL_ISUPPORTS
567 NotificationCallbacks() {
568 }
570 NS_IMETHOD GetInterface(const nsIID& iid, void* *result) {
571 nsresult rv = NS_ERROR_FAILURE;
573 if (iid.Equals(NS_GET_IID(nsIChannelEventSink))) {
574 TestChannelEventSink *sink;
576 sink = new TestChannelEventSink();
577 if (sink == nullptr)
578 return NS_ERROR_OUT_OF_MEMORY;
579 NS_ADDREF(sink);
580 rv = sink->QueryInterface(iid, result);
581 NS_RELEASE(sink);
582 }
584 if (iid.Equals(NS_GET_IID(nsIAuthPrompt))) {
585 TestAuthPrompt *prompt;
587 prompt = new TestAuthPrompt();
588 if (prompt == nullptr)
589 return NS_ERROR_OUT_OF_MEMORY;
590 NS_ADDREF(prompt);
591 rv = prompt->QueryInterface(iid, result);
592 NS_RELEASE(prompt);
593 }
594 return rv;
595 }
596 };
598 NS_IMPL_ISUPPORTS(NotificationCallbacks, nsIInterfaceRequestor)
600 //-----------------------------------------------------------------------------
601 // helpers...
602 //-----------------------------------------------------------------------------
604 nsresult StartLoadingURL(const char* aUrlString)
605 {
606 nsresult rv;
608 nsCOMPtr<nsIIOService> pService(do_GetService(kIOServiceCID, &rv));
609 if (pService) {
610 nsCOMPtr<nsIURI> pURL;
612 rv = pService->NewURI(nsDependentCString(aUrlString), nullptr, nullptr, getter_AddRefs(pURL));
613 if (NS_FAILED(rv)) {
614 LOG(("ERROR: NewURI failed for %s [rv=%x]\n", aUrlString));
615 return rv;
616 }
617 nsCOMPtr<nsIChannel> pChannel;
619 NotificationCallbacks* callbacks = new NotificationCallbacks();
620 if (!callbacks) {
621 LOG(("Failed to create a new consumer!"));
622 return NS_ERROR_OUT_OF_MEMORY;;
623 }
624 NS_ADDREF(callbacks);
626 // Async reading thru the calls of the event sink interface
627 rv = NS_NewChannel(getter_AddRefs(pChannel), pURL, pService,
628 nullptr, // loadGroup
629 callbacks); // notificationCallbacks
630 NS_RELEASE(callbacks);
631 if (NS_FAILED(rv)) {
632 LOG(("ERROR: NS_OpenURI failed for %s [rv=%x]\n", aUrlString, rv));
633 return rv;
634 }
636 nsCOMPtr<nsITimedChannel> timed(do_QueryInterface(pChannel));
637 if (timed)
638 timed->SetTimingEnabled(true);
640 nsCOMPtr<nsIWritablePropertyBag2> props = do_QueryInterface(pChannel);
641 if (props) {
642 rv = props->SetPropertyAsInterface(NS_LITERAL_STRING("test.foo"),
643 pURL);
644 if (NS_SUCCEEDED(rv)) {
645 LOG(("set prop 'test.foo'\n"));
646 }
647 }
649 /*
650 You may optionally add/set other headers on this
651 request object. This is done by QI for the specific
652 protocolConnection.
653 */
654 nsCOMPtr<nsIHttpChannel> pHTTPCon(do_QueryInterface(pChannel));
656 if (pHTTPCon) {
657 // Setting a sample header.
658 rv = pHTTPCon->SetRequestHeader(NS_LITERAL_CSTRING("sample-header"),
659 NS_LITERAL_CSTRING("Sample-Value"),
660 false);
661 if (NS_FAILED(rv)) return rv;
662 }
663 InputTestConsumer* listener;
665 listener = new InputTestConsumer;
666 NS_IF_ADDREF(listener);
667 if (!listener) {
668 NS_ERROR("Failed to create a new stream listener!");
669 return NS_ERROR_OUT_OF_MEMORY;;
670 }
672 URLLoadInfo* info;
673 info = new URLLoadInfo(aUrlString);
674 NS_IF_ADDREF(info);
675 if (!info) {
676 NS_ERROR("Failed to create a load info!");
677 return NS_ERROR_OUT_OF_MEMORY;
678 }
680 if (gResume) {
681 nsCOMPtr<nsIResumableChannel> res = do_QueryInterface(pChannel);
682 if (!res) {
683 NS_ERROR("Channel is not resumable!");
684 return NS_ERROR_UNEXPECTED;
685 }
686 nsAutoCString id;
687 if (gEntityID)
688 id = gEntityID;
689 LOG(("* resuming at %llu bytes, with entity id |%s|\n", gStartAt, id.get()));
690 res->ResumeAt(gStartAt, id);
691 }
692 rv = pChannel->AsyncOpen(listener, // IStreamListener consumer
693 info);
695 if (NS_SUCCEEDED(rv)) {
696 gKeepRunning++;
697 }
698 else {
699 LOG(("ERROR: AsyncOpen failed [rv=%x]\n", rv));
700 }
701 NS_RELEASE(listener);
702 NS_RELEASE(info);
703 }
705 return rv;
706 }
708 static int32_t
709 FindChar(nsCString& buffer, char c)
710 {
711 const char *b;
712 int32_t len = NS_CStringGetData(buffer, &b);
714 for (int32_t offset = 0; offset < len; ++offset) {
715 if (b[offset] == c)
716 return offset;
717 }
719 return -1;
720 }
723 static void
724 StripChar(nsCString& buffer, char c)
725 {
726 const char *b;
727 uint32_t len = NS_CStringGetData(buffer, &b) - 1;
729 for (; len > 0; --len) {
730 if (b[len] == c) {
731 buffer.Cut(len, 1);
732 NS_CStringGetData(buffer, &b);
733 }
734 }
735 }
737 nsresult LoadURLsFromFile(char *aFileName)
738 {
739 nsresult rv = NS_OK;
740 int32_t len, offset;
741 PRFileDesc* fd;
742 char buffer[1024];
743 nsCString fileBuffer;
744 nsCString urlString;
746 fd = PR_Open(aFileName, PR_RDONLY, 777);
747 if (!fd) {
748 return NS_ERROR_FAILURE;
749 }
751 // Keep reading the file until EOF (or an error) is reached...
752 do {
753 len = PR_Read(fd, buffer, sizeof(buffer));
754 if (len>0) {
755 fileBuffer.Append(buffer, len);
756 // Treat each line as a URL...
757 while ((offset = FindChar(fileBuffer, '\n')) != -1) {
758 urlString = StringHead(fileBuffer, offset);
759 fileBuffer.Cut(0, offset+1);
761 StripChar(urlString, '\r');
762 if (urlString.Length()) {
763 LOG(("\t%s\n", urlString.get()));
764 rv = StartLoadingURL(urlString.get());
765 if (NS_FAILED(rv)) {
766 // No need to log an error -- StartLoadingURL already
767 // did that for us, probably.
768 PR_Close(fd);
769 return rv;
770 }
771 }
772 }
773 }
774 } while (len>0);
776 // If anything is left in the fileBuffer, treat it as a URL...
777 StripChar(fileBuffer, '\r');
778 if (fileBuffer.Length()) {
779 LOG(("\t%s\n", fileBuffer.get()));
780 StartLoadingURL(fileBuffer.get());
781 }
783 PR_Close(fd);
784 return NS_OK;
785 }
788 nsresult LoadURLFromConsole()
789 {
790 char buffer[1024];
791 printf("Enter URL (\"q\" to start): ");
792 unused << scanf("%s", buffer);
793 if (buffer[0]=='q')
794 gAskUserForInput = false;
795 else
796 StartLoadingURL(buffer);
797 return NS_OK;
798 }
800 } // namespace
802 using namespace TestProtocols;
804 int
805 main(int argc, char* argv[])
806 {
807 if (test_common_init(&argc, &argv) != 0)
808 return -1;
810 nsresult rv= (nsresult)-1;
811 if (argc < 2) {
812 printf("usage: %s [-verbose] [-file <name>] [-resume <startoffset>"
813 "[-entityid <entityid>]] [-proxy <proxy>] [-pac <pacURL>]"
814 "[-console] <url> <url> ... \n", argv[0]);
815 return -1;
816 }
818 #if defined(PR_LOGGING)
819 gTestLog = PR_NewLogModule("Test");
820 #endif
822 /*
823 The following code only deals with XPCOM registration stuff. and setting
824 up the event queues. Copied from TestSocketIO.cpp
825 */
827 rv = NS_InitXPCOM2(nullptr, nullptr, nullptr);
828 if (NS_FAILED(rv)) return -1;
830 {
831 int i;
832 LOG(("Trying to load:\n"));
833 for (i=1; i<argc; i++) {
834 // Turn on verbose printing...
835 if (PL_strcasecmp(argv[i], "-verbose") == 0) {
836 gVerbose = true;
837 continue;
838 }
840 // Turn on netlib tracing...
841 if (PL_strcasecmp(argv[i], "-file") == 0) {
842 LoadURLsFromFile(argv[++i]);
843 continue;
844 }
846 if (PL_strcasecmp(argv[i], "-console") == 0) {
847 gAskUserForInput = true;
848 continue;
849 }
851 if (PL_strcasecmp(argv[i], "-resume") == 0) {
852 gResume = true;
853 PR_sscanf(argv[++i], "%llu", &gStartAt);
854 continue;
855 }
857 if (PL_strcasecmp(argv[i], "-entityid") == 0) {
858 gEntityID = argv[++i];
859 continue;
860 }
862 if (PL_strcasecmp(argv[i], "-proxy") == 0) {
863 SetHttpProxy(argv[++i]);
864 continue;
865 }
867 if (PL_strcasecmp(argv[i], "-pac") == 0) {
868 SetPACFile(argv[++i]);
869 continue;
870 }
872 LOG(("\t%s\n", argv[i]));
873 rv = StartLoadingURL(argv[i]);
874 }
875 // Enter the message pump to allow the URL load to proceed.
876 PumpEvents();
877 } // this scopes the nsCOMPtrs
878 // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM
879 NS_ShutdownXPCOM(nullptr);
880 return NS_FAILED(rv) ? -1 : 0;
881 }