1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim: set ts=4 sw=4 et cindent: */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is mozilla.org code.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
40 The TestProtocols tests the basic protocols architecture and can
41 be used to test individual protocols as well. If this grows too
42 big then we should split it to individual protocols.
44 -Gagan Saksena 04/29/99
47 #include "TestCommon.h"
60 #include "nsIIOService.h"
61 #include "nsIServiceManager.h"
62 #include "nsIStreamListener.h"
63 #include "nsIInputStream.h"
64 #include "nsIInputStream.h"
66 #include "nsIChannel.h"
67 #include "nsIResumableChannel.h"
69 #include "nsIHttpChannel.h"
70 #include "nsIHttpChannelInternal.h"
71 #include "nsIHttpHeaderVisitor.h"
72 #include "nsIChannelEventSink.h"
73 #include "nsIInterfaceRequestor.h"
74 #include "nsIInterfaceRequestorUtils.h"
75 #include "nsIDNSService.h"
76 #include "nsIAuthPrompt.h"
77 #include "nsIPrefService.h"
78 #include "nsIPrefBranch.h"
79 #include "nsIPropertyBag2.h"
80 #include "nsIWritablePropertyBag2.h"
81 #include "nsChannelProperties.h"
83 #include "nsISimpleEnumerator.h"
84 #include "nsStringAPI.h"
85 #include "nsNetUtil.h"
91 namespace TestProtocols
{
93 #if defined(PR_LOGGING)
95 // set NSPR_LOG_MODULES=Test:5
97 static PRLogModuleInfo
*gTestLog
= nsnull
;
99 #define LOG(args) PR_LOG(gTestLog, PR_LOG_DEBUG, args)
101 static NS_DEFINE_CID(kIOServiceCID
, NS_IOSERVICE_CID
);
103 //static PRTime gElapsedTime; // enable when we time it...
104 static int gKeepRunning
= 0;
105 static PRBool gVerbose
= PR_FALSE
;
106 static PRBool gAskUserForInput
= PR_FALSE
;
107 static PRBool gResume
= PR_FALSE
;
108 static PRUint64 gStartAt
= 0;
110 static const char* gEntityID
;
112 //-----------------------------------------------------------------------------
113 // Set proxy preferences for testing
114 //-----------------------------------------------------------------------------
117 SetHttpProxy(const char *proxy
)
119 const char *colon
= strchr(proxy
, ':');
122 NS_WARNING("invalid proxy token; use host:port");
123 return NS_ERROR_UNEXPECTED
;
125 int port
= atoi(colon
+ 1);
128 NS_WARNING("invalid proxy port; must be an integer");
129 return NS_ERROR_UNEXPECTED
;
131 nsCAutoString proxyHost
;
132 proxyHost
= Substring(proxy
, colon
);
134 nsCOMPtr
<nsIPrefBranch
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
137 prefs
->SetCharPref("network.proxy.http", proxyHost
.get());
138 prefs
->SetIntPref("network.proxy.http_port", port
);
139 prefs
->SetIntPref("network.proxy.type", 1); // manual proxy config
141 LOG(("connecting via proxy=%s:%d\n", proxyHost
.get(), port
));
146 SetPACFile(const char* pacURL
)
148 nsCOMPtr
<nsIPrefBranch
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
151 prefs
->SetCharPref("network.proxy.autoconfig_url", pacURL
);
152 prefs
->SetIntPref("network.proxy.type", 2); // PAC file
154 LOG(("connecting using PAC file %s\n", pacURL
));
158 //-----------------------------------------------------------------------------
160 //-----------------------------------------------------------------------------
162 class HeaderVisitor
: public nsIHttpHeaderVisitor
166 NS_DECL_NSIHTTPHEADERVISITOR
169 virtual ~HeaderVisitor() {}
171 NS_IMPL_ISUPPORTS1(HeaderVisitor
, nsIHttpHeaderVisitor
)
174 HeaderVisitor::VisitHeader(const nsACString
&header
, const nsACString
&value
)
177 PromiseFlatCString(header
).get(),
178 PromiseFlatCString(value
).get()));
182 //-----------------------------------------------------------------------------
184 //-----------------------------------------------------------------------------
186 class URLLoadInfo
: public nsISupports
190 URLLoadInfo(const char* aUrl
);
191 virtual ~URLLoadInfo();
193 // ISupports interface...
196 const char* Name() { return mURLString
.get(); }
200 nsCString mURLString
;
203 URLLoadInfo::URLLoadInfo(const char *aUrl
) : mURLString(aUrl
)
206 mConnectTime
= mTotalTime
= PR_Now();
209 URLLoadInfo::~URLLoadInfo()
214 NS_IMPL_THREADSAFE_ISUPPORTS0(URLLoadInfo
)
216 //-----------------------------------------------------------------------------
217 // TestChannelEventSink
218 //-----------------------------------------------------------------------------
220 class TestChannelEventSink
: public nsIChannelEventSink
224 NS_DECL_NSICHANNELEVENTSINK
226 TestChannelEventSink();
227 virtual ~TestChannelEventSink();
230 TestChannelEventSink::TestChannelEventSink()
234 TestChannelEventSink::~TestChannelEventSink()
239 NS_IMPL_ISUPPORTS1(TestChannelEventSink
, nsIChannelEventSink
)
242 TestChannelEventSink::OnChannelRedirect(nsIChannel
*channel
,
243 nsIChannel
*newChannel
,
246 LOG(("\n+++ TestChannelEventSink::OnChannelRedirect (with flags %x) +++\n",
251 //-----------------------------------------------------------------------------
253 //-----------------------------------------------------------------------------
255 class TestAuthPrompt
: public nsIAuthPrompt
259 NS_DECL_NSIAUTHPROMPT
262 virtual ~TestAuthPrompt();
265 NS_IMPL_ISUPPORTS1(TestAuthPrompt
, nsIAuthPrompt
)
267 TestAuthPrompt::TestAuthPrompt()
271 TestAuthPrompt::~TestAuthPrompt()
276 TestAuthPrompt::Prompt(const PRUnichar
*dialogTitle
,
277 const PRUnichar
*text
,
278 const PRUnichar
*passwordRealm
,
279 PRUint32 savePassword
,
280 const PRUnichar
*defaultText
,
285 return NS_ERROR_NOT_IMPLEMENTED
;
289 TestAuthPrompt::PromptUsernameAndPassword(const PRUnichar
*dialogTitle
,
290 const PRUnichar
*dialogText
,
291 const PRUnichar
*passwordRealm
,
292 PRUint32 savePassword
,
297 NS_ConvertUTF16toUTF8
text(passwordRealm
);
298 printf("* --------------------------------------------------------------------------- *\n");
299 printf("* Authentication Required [%s]\n", text
.get());
300 printf("* --------------------------------------------------------------------------- *\n");
305 printf("Enter username: ");
306 fgets(buf
, sizeof(buf
), stdin
);
308 buf
[n
-1] = '\0'; // trim trailing newline
309 *user
= NS_StringCloneData(NS_ConvertUTF8toUTF16(buf
));
313 p
= getpass("Enter password: ");
315 printf("Enter password: ");
316 fgets(buf
, sizeof(buf
), stdin
);
318 buf
[n
-1] = '\0'; // trim trailing newline
321 *pwd
= NS_StringCloneData(NS_ConvertUTF8toUTF16(p
));
324 memset(buf
, 0, sizeof(buf
));
331 TestAuthPrompt::PromptPassword(const PRUnichar
*dialogTitle
,
332 const PRUnichar
*text
,
333 const PRUnichar
*passwordRealm
,
334 PRUint32 savePassword
,
339 return NS_ERROR_NOT_IMPLEMENTED
;
342 //-----------------------------------------------------------------------------
344 //-----------------------------------------------------------------------------
346 class InputTestConsumer
: public nsIStreamListener
351 virtual ~InputTestConsumer();
354 NS_DECL_NSIREQUESTOBSERVER
355 NS_DECL_NSISTREAMLISTENER
358 InputTestConsumer::InputTestConsumer()
362 InputTestConsumer::~InputTestConsumer()
366 NS_IMPL_ISUPPORTS2(InputTestConsumer
, nsIStreamListener
, nsIRequestObserver
)
369 InputTestConsumer::OnStartRequest(nsIRequest
*request
, nsISupports
* context
)
371 LOG(("InputTestConsumer::OnStartRequest\n"));
373 URLLoadInfo
* info
= (URLLoadInfo
*)context
;
375 info
->mConnectTime
= PR_Now() - info
->mConnectTime
;
378 LOG(("\nStarted loading: %s\n", info
? info
->Name() : "UNKNOWN URL"));
382 nsCOMPtr
<nsIChannel
> channel
= do_QueryInterface(request
);
385 channel
->GetStatus(&status
);
386 LOG(("Channel Status: %08x\n", status
));
387 if (NS_SUCCEEDED(status
)) {
388 LOG(("Channel Info:\n"));
390 channel
->GetName(value
);
391 LOG(("\tName: %s\n", value
.get()));
393 channel
->GetContentType(value
);
394 LOG(("\tContent-Type: %s\n", value
.get()));
396 channel
->GetContentCharset(value
);
397 LOG(("\tContent-Charset: %s\n", value
.get()));
400 if (NS_SUCCEEDED(channel
->GetContentLength(&length
)))
401 LOG(("\tContent-Length: %d\n", length
));
403 LOG(("\tContent-Length: Unknown\n"));
406 nsCOMPtr
<nsISupports
> owner
;
407 channel
->GetOwner(getter_AddRefs(owner
));
408 LOG(("\tChannel Owner: %x\n", owner
.get()));
411 nsCOMPtr
<nsIPropertyBag2
> props
= do_QueryInterface(request
);
413 nsCOMPtr
<nsIURI
> foo
;
414 props
->GetPropertyAsInterface(NS_LITERAL_STRING("test.foo"),
416 getter_AddRefs(foo
));
420 LOG(("\ttest.foo: %s\n", spec
.get()));
424 nsCOMPtr
<nsIPropertyBag2
> propbag
= do_QueryInterface(request
);
427 nsresult rv
= propbag
->GetPropertyAsInt64(NS_CHANNEL_PROP_CONTENT_LENGTH
,
429 if (NS_SUCCEEDED(rv
))
430 LOG(("\t64-bit length: %lli\n", len
));
433 nsCOMPtr
<nsIHttpChannelInternal
> httpChannelInt(do_QueryInterface(request
));
434 if (httpChannelInt
) {
435 PRUint32 majorVer
, minorVer
;
436 nsresult rv
= httpChannelInt
->GetResponseVersion(&majorVer
, &minorVer
);
437 if (NS_SUCCEEDED(rv
))
438 LOG(("HTTP Response version: %u.%u\n", majorVer
, minorVer
));
440 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(request
));
442 HeaderVisitor
*visitor
= new HeaderVisitor();
444 return NS_ERROR_OUT_OF_MEMORY
;
447 LOG(("HTTP request headers:\n"));
448 httpChannel
->VisitRequestHeaders(visitor
);
450 LOG(("HTTP response headers:\n"));
451 httpChannel
->VisitResponseHeaders(visitor
);
456 nsCOMPtr
<nsIResumableChannel
> resChannel
= do_QueryInterface(request
);
458 LOG(("Resumable entity identification:\n"));
459 nsCAutoString entityID
;
460 nsresult rv
= resChannel
->GetEntityID(entityID
);
461 if (NS_SUCCEEDED(rv
)) {
462 LOG(("\t|%s|\n", entityID
.get()));
473 InputTestConsumer::OnDataAvailable(nsIRequest
*request
,
474 nsISupports
* context
,
475 nsIInputStream
*aIStream
,
476 PRUint32 aSourceOffset
,
482 URLLoadInfo
* info
= (URLLoadInfo
*)context
;
485 size
= PR_MIN(aLength
, sizeof(buf
));
487 rv
= aIStream
->Read(buf
, size
, &amt
);
489 NS_ASSERTION((NS_BASE_STREAM_WOULD_BLOCK
!= rv
),
490 "The stream should never block.");
498 info
->mBytesRead
+= amt
;
507 InputTestConsumer::OnStopRequest(nsIRequest
*request
, nsISupports
* context
,
510 LOG(("InputTestConsumer::OnStopRequest [status=%x]\n", aStatus
));
512 URLLoadInfo
* info
= (URLLoadInfo
*)context
;
518 PRBool bHTTPURL
= PR_FALSE
;
520 info
->mTotalTime
= PR_Now() - info
->mTotalTime
;
522 connectTime
= (info
->mConnectTime
/1000.0)/1000.0;
523 readTime
= ((info
->mTotalTime
-info
->mConnectTime
)/1000.0)/1000.0;
525 nsCOMPtr
<nsIHttpChannel
> pHTTPCon(do_QueryInterface(request
));
527 pHTTPCon
->GetResponseStatus(&httpStatus
);
531 LOG(("\nFinished loading: %s Status Code: %x\n", info
->Name(), aStatus
));
533 LOG(("\tHTTP Status: %u\n", httpStatus
));
534 if (NS_ERROR_UNKNOWN_HOST
== aStatus
||
535 NS_ERROR_UNKNOWN_PROXY_HOST
== aStatus
) {
536 LOG(("\tDNS lookup failed.\n"));
538 LOG(("\tTime to connect: %.3f seconds\n", connectTime
));
539 LOG(("\tTime to read: %.3f seconds.\n", readTime
));
540 LOG(("\tRead: %lld bytes.\n", info
->mBytesRead
.mValue
));
541 if (info
->mBytesRead
== nsInt64(0)) {
542 } else if (readTime
> 0.0) {
543 LOG(("\tThroughput: %.0f bps.\n", (PRFloat64
)(info
->mBytesRead
*nsInt64(8))/readTime
));
545 LOG(("\tThroughput: REAL FAST!!\n"));
548 LOG(("\nFinished loading: UNKNOWN URL. Status Code: %x\n", aStatus
));
551 if (--gKeepRunning
== 0)
556 //-----------------------------------------------------------------------------
557 // NotificationCallbacks
558 //-----------------------------------------------------------------------------
560 class NotificationCallbacks
: public nsIInterfaceRequestor
{
564 NotificationCallbacks() {
567 NS_IMETHOD
GetInterface(const nsIID
& iid
, void* *result
) {
568 nsresult rv
= NS_ERROR_FAILURE
;
570 if (iid
.Equals(NS_GET_IID(nsIChannelEventSink
))) {
571 TestChannelEventSink
*sink
;
573 sink
= new TestChannelEventSink();
575 return NS_ERROR_OUT_OF_MEMORY
;
577 rv
= sink
->QueryInterface(iid
, result
);
581 if (iid
.Equals(NS_GET_IID(nsIAuthPrompt
))) {
582 TestAuthPrompt
*prompt
;
584 prompt
= new TestAuthPrompt();
585 if (prompt
== nsnull
)
586 return NS_ERROR_OUT_OF_MEMORY
;
588 rv
= prompt
->QueryInterface(iid
, result
);
595 NS_IMPL_ISUPPORTS1(NotificationCallbacks
, nsIInterfaceRequestor
)
597 //-----------------------------------------------------------------------------
599 //-----------------------------------------------------------------------------
601 nsresult
StartLoadingURL(const char* aUrlString
)
605 nsCOMPtr
<nsIIOService
> pService(do_GetService(kIOServiceCID
, &rv
));
607 nsCOMPtr
<nsIURI
> pURL
;
609 rv
= pService
->NewURI(nsDependentCString(aUrlString
), nsnull
, nsnull
, getter_AddRefs(pURL
));
611 LOG(("ERROR: NewURI failed for %s [rv=%x]\n", aUrlString
));
614 nsCOMPtr
<nsIChannel
> pChannel
;
616 NotificationCallbacks
* callbacks
= new NotificationCallbacks();
618 LOG(("Failed to create a new consumer!"));
619 return NS_ERROR_OUT_OF_MEMORY
;;
621 NS_ADDREF(callbacks
);
623 // Async reading thru the calls of the event sink interface
624 rv
= NS_NewChannel(getter_AddRefs(pChannel
), pURL
, pService
,
626 callbacks
); // notificationCallbacks
627 NS_RELEASE(callbacks
);
629 LOG(("ERROR: NS_OpenURI failed for %s [rv=%x]\n", aUrlString
, rv
));
633 nsCOMPtr
<nsIWritablePropertyBag2
> props
= do_QueryInterface(pChannel
);
635 rv
= props
->SetPropertyAsInterface(NS_LITERAL_STRING("test.foo"),
637 if (NS_SUCCEEDED(rv
))
638 LOG(("set prop 'test.foo'\n"));
642 You may optionally add/set other headers on this
643 request object. This is done by QI for the specific
646 nsCOMPtr
<nsIHttpChannel
> pHTTPCon(do_QueryInterface(pChannel
));
649 // Setting a sample header.
650 rv
= pHTTPCon
->SetRequestHeader(NS_LITERAL_CSTRING("sample-header"),
651 NS_LITERAL_CSTRING("Sample-Value"),
653 if (NS_FAILED(rv
)) return rv
;
655 InputTestConsumer
* listener
;
657 listener
= new InputTestConsumer
;
658 NS_IF_ADDREF(listener
);
660 NS_ERROR("Failed to create a new stream listener!");
661 return NS_ERROR_OUT_OF_MEMORY
;;
665 info
= new URLLoadInfo(aUrlString
);
668 NS_ERROR("Failed to create a load info!");
669 return NS_ERROR_OUT_OF_MEMORY
;
673 nsCOMPtr
<nsIResumableChannel
> res
= do_QueryInterface(pChannel
);
675 NS_ERROR("Channel is not resumable!");
676 return NS_ERROR_UNEXPECTED
;
681 LOG(("* resuming at %llu bytes, with entity id |%s|\n", gStartAt
, id
.get()));
682 res
->ResumeAt(gStartAt
, id
);
684 rv
= pChannel
->AsyncOpen(listener
, // IStreamListener consumer
687 if (NS_SUCCEEDED(rv
)) {
691 LOG(("ERROR: AsyncOpen failed [rv=%x]\n", rv
));
693 NS_RELEASE(listener
);
701 FindChar(nsCString
& buffer
, char c
)
704 PRInt32 len
= NS_CStringGetData(buffer
, &b
);
706 for (PRInt32 offset
= 0; offset
< len
; ++offset
) {
716 StripChar(nsCString
& buffer
, char c
)
719 PRUint32 len
= NS_CStringGetData(buffer
, &b
) - 1;
721 for (; len
> 0; --len
) {
724 NS_CStringGetData(buffer
, &b
);
729 nsresult
LoadURLsFromFile(char *aFileName
)
735 nsCString fileBuffer
;
738 fd
= PR_Open(aFileName
, PR_RDONLY
, 777);
740 return NS_ERROR_FAILURE
;
743 // Keep reading the file until EOF (or an error) is reached...
745 len
= PR_Read(fd
, buffer
, sizeof(buffer
));
747 fileBuffer
.Append(buffer
, len
);
748 // Treat each line as a URL...
749 while ((offset
= FindChar(fileBuffer
, '\n')) != -1) {
750 urlString
= StringHead(fileBuffer
, offset
);
751 fileBuffer
.Cut(0, offset
+1);
753 StripChar(urlString
, '\r');
754 if (urlString
.Length()) {
755 LOG(("\t%s\n", urlString
.get()));
756 rv
= StartLoadingURL(urlString
.get());
762 // If anything is left in the fileBuffer, treat it as a URL...
763 StripChar(fileBuffer
, '\r');
764 if (fileBuffer
.Length()) {
765 LOG(("\t%s\n", fileBuffer
.get()));
766 StartLoadingURL(fileBuffer
.get());
774 nsresult
LoadURLFromConsole()
777 printf("Enter URL (\"q\" to start): ");
780 gAskUserForInput
= PR_FALSE
;
782 StartLoadingURL(buffer
);
788 using namespace TestProtocols
;
791 main(int argc
, char* argv
[])
793 if (test_common_init(&argc
, &argv
) != 0)
796 nsresult rv
= (nsresult
)-1;
798 printf("usage: %s [-verbose] [-file <name>] [-resume <startoffset>"
799 "[-entityid <entityid>]] [-proxy <proxy>] [-pac <pacURL>]"
800 "[-console] <url> <url> ... \n", argv
[0]);
804 #if defined(PR_LOGGING)
805 gTestLog
= PR_NewLogModule("Test");
809 The following code only deals with XPCOM registration stuff. and setting
810 up the event queues. Copied from TestSocketIO.cpp
813 rv
= NS_InitXPCOM2(nsnull
, nsnull
, nsnull
);
814 if (NS_FAILED(rv
)) return rv
;
818 LOG(("Trying to load:\n"));
819 for (i
=1; i
<argc
; i
++) {
820 // Turn on verbose printing...
821 if (PL_strcasecmp(argv
[i
], "-verbose") == 0) {
826 // Turn on netlib tracing...
827 if (PL_strcasecmp(argv
[i
], "-file") == 0) {
828 LoadURLsFromFile(argv
[++i
]);
832 if (PL_strcasecmp(argv
[i
], "-console") == 0) {
833 gAskUserForInput
= PR_TRUE
;
837 if (PL_strcasecmp(argv
[i
], "-resume") == 0) {
839 PR_sscanf(argv
[++i
], "%llu", &gStartAt
);
843 if (PL_strcasecmp(argv
[i
], "-entityid") == 0) {
844 gEntityID
= argv
[++i
];
848 if (PL_strcasecmp(argv
[i
], "-proxy") == 0) {
849 SetHttpProxy(argv
[++i
]);
853 if (PL_strcasecmp(argv
[i
], "-pac") == 0) {
854 SetPACFile(argv
[++i
]);
858 LOG(("\t%s\n", argv
[i
]));
859 rv
= StartLoadingURL(argv
[i
]);
861 // Enter the message pump to allow the URL load to proceed.
863 } // this scopes the nsCOMPtrs
864 // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM
865 NS_ShutdownXPCOM(nsnull
);