|
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/. */ |
|
6 |
|
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. |
|
11 |
|
12 -Gagan Saksena 04/29/99 |
|
13 */ |
|
14 |
|
15 #include "TestCommon.h" |
|
16 #include <algorithm> |
|
17 |
|
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" |
|
55 |
|
56 #include "nsISimpleEnumerator.h" |
|
57 #include "nsStringAPI.h" |
|
58 #include "nsNetUtil.h" |
|
59 #include "prlog.h" |
|
60 |
|
61 using namespace mozilla; |
|
62 |
|
63 namespace TestProtocols { |
|
64 |
|
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) |
|
72 |
|
73 static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID); |
|
74 |
|
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; |
|
81 |
|
82 static const char* gEntityID; |
|
83 |
|
84 //----------------------------------------------------------------------------- |
|
85 // Set proxy preferences for testing |
|
86 //----------------------------------------------------------------------------- |
|
87 |
|
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); |
|
105 |
|
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 } |
|
116 |
|
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 } |
|
129 |
|
130 //----------------------------------------------------------------------------- |
|
131 // Timing information |
|
132 //----------------------------------------------------------------------------- |
|
133 |
|
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 } |
|
162 |
|
163 //----------------------------------------------------------------------------- |
|
164 // HeaderVisitor |
|
165 //----------------------------------------------------------------------------- |
|
166 |
|
167 class HeaderVisitor : public nsIHttpHeaderVisitor |
|
168 { |
|
169 public: |
|
170 NS_DECL_ISUPPORTS |
|
171 NS_DECL_NSIHTTPHEADERVISITOR |
|
172 |
|
173 HeaderVisitor() { } |
|
174 virtual ~HeaderVisitor() {} |
|
175 }; |
|
176 NS_IMPL_ISUPPORTS(HeaderVisitor, nsIHttpHeaderVisitor) |
|
177 |
|
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 } |
|
186 |
|
187 //----------------------------------------------------------------------------- |
|
188 // URLLoadInfo |
|
189 //----------------------------------------------------------------------------- |
|
190 |
|
191 class URLLoadInfo : public nsISupports |
|
192 { |
|
193 public: |
|
194 |
|
195 URLLoadInfo(const char* aUrl); |
|
196 virtual ~URLLoadInfo(); |
|
197 |
|
198 // ISupports interface... |
|
199 NS_DECL_THREADSAFE_ISUPPORTS |
|
200 |
|
201 const char* Name() { return mURLString.get(); } |
|
202 int64_t mBytesRead; |
|
203 PRTime mTotalTime; |
|
204 PRTime mConnectTime; |
|
205 nsCString mURLString; |
|
206 }; |
|
207 |
|
208 URLLoadInfo::URLLoadInfo(const char *aUrl) : mURLString(aUrl) |
|
209 { |
|
210 mBytesRead = 0; |
|
211 mConnectTime = mTotalTime = PR_Now(); |
|
212 } |
|
213 |
|
214 URLLoadInfo::~URLLoadInfo() |
|
215 { |
|
216 } |
|
217 |
|
218 |
|
219 NS_IMPL_ISUPPORTS0(URLLoadInfo) |
|
220 |
|
221 //----------------------------------------------------------------------------- |
|
222 // TestChannelEventSink |
|
223 //----------------------------------------------------------------------------- |
|
224 |
|
225 class TestChannelEventSink : public nsIChannelEventSink |
|
226 { |
|
227 public: |
|
228 NS_DECL_ISUPPORTS |
|
229 NS_DECL_NSICHANNELEVENTSINK |
|
230 |
|
231 TestChannelEventSink(); |
|
232 virtual ~TestChannelEventSink(); |
|
233 }; |
|
234 |
|
235 TestChannelEventSink::TestChannelEventSink() |
|
236 { |
|
237 } |
|
238 |
|
239 TestChannelEventSink::~TestChannelEventSink() |
|
240 { |
|
241 } |
|
242 |
|
243 |
|
244 NS_IMPL_ISUPPORTS(TestChannelEventSink, nsIChannelEventSink) |
|
245 |
|
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 } |
|
257 |
|
258 //----------------------------------------------------------------------------- |
|
259 // TestAuthPrompt |
|
260 //----------------------------------------------------------------------------- |
|
261 |
|
262 class TestAuthPrompt : public nsIAuthPrompt |
|
263 { |
|
264 public: |
|
265 NS_DECL_ISUPPORTS |
|
266 NS_DECL_NSIAUTHPROMPT |
|
267 |
|
268 TestAuthPrompt(); |
|
269 virtual ~TestAuthPrompt(); |
|
270 }; |
|
271 |
|
272 NS_IMPL_ISUPPORTS(TestAuthPrompt, nsIAuthPrompt) |
|
273 |
|
274 TestAuthPrompt::TestAuthPrompt() |
|
275 { |
|
276 } |
|
277 |
|
278 TestAuthPrompt::~TestAuthPrompt() |
|
279 { |
|
280 } |
|
281 |
|
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 } |
|
294 |
|
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"); |
|
308 |
|
309 char buf[256]; |
|
310 int n; |
|
311 |
|
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)); |
|
317 |
|
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)); |
|
329 |
|
330 // zap buf |
|
331 memset(buf, 0, sizeof(buf)); |
|
332 |
|
333 *_retval = true; |
|
334 return NS_OK; |
|
335 } |
|
336 |
|
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 } |
|
348 |
|
349 //----------------------------------------------------------------------------- |
|
350 // InputTestConsumer |
|
351 //----------------------------------------------------------------------------- |
|
352 |
|
353 class InputTestConsumer : public nsIStreamListener |
|
354 { |
|
355 public: |
|
356 |
|
357 InputTestConsumer(); |
|
358 virtual ~InputTestConsumer(); |
|
359 |
|
360 NS_DECL_ISUPPORTS |
|
361 NS_DECL_NSIREQUESTOBSERVER |
|
362 NS_DECL_NSISTREAMLISTENER |
|
363 }; |
|
364 |
|
365 InputTestConsumer::InputTestConsumer() |
|
366 { |
|
367 } |
|
368 |
|
369 InputTestConsumer::~InputTestConsumer() |
|
370 { |
|
371 } |
|
372 |
|
373 NS_IMPL_ISUPPORTS(InputTestConsumer, nsIStreamListener, nsIRequestObserver) |
|
374 |
|
375 NS_IMETHODIMP |
|
376 InputTestConsumer::OnStartRequest(nsIRequest *request, nsISupports* context) |
|
377 { |
|
378 LOG(("InputTestConsumer::OnStartRequest\n")); |
|
379 |
|
380 URLLoadInfo* info = (URLLoadInfo*)context; |
|
381 if (info) |
|
382 info->mConnectTime = PR_Now() - info->mConnectTime; |
|
383 |
|
384 if (gVerbose) { |
|
385 LOG(("\nStarted loading: %s\n", info ? info->Name() : "UNKNOWN URL")); |
|
386 } |
|
387 |
|
388 nsAutoCString value; |
|
389 |
|
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")); |
|
397 |
|
398 channel->GetName(value); |
|
399 LOG(("\tName: %s\n", value.get())); |
|
400 |
|
401 channel->GetContentType(value); |
|
402 LOG(("\tContent-Type: %s\n", value.get())); |
|
403 |
|
404 channel->GetContentCharset(value); |
|
405 LOG(("\tContent-Charset: %s\n", value.get())); |
|
406 |
|
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 } |
|
414 |
|
415 nsCOMPtr<nsISupports> owner; |
|
416 channel->GetOwner(getter_AddRefs(owner)); |
|
417 LOG(("\tChannel Owner: %x\n", owner.get())); |
|
418 } |
|
419 |
|
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 } |
|
432 |
|
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); |
|
447 |
|
448 LOG(("HTTP request headers:\n")); |
|
449 httpChannel->VisitRequestHeaders(visitor); |
|
450 |
|
451 LOG(("HTTP response headers:\n")); |
|
452 httpChannel->VisitResponseHeaders(visitor); |
|
453 |
|
454 NS_RELEASE(visitor); |
|
455 } |
|
456 |
|
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 } |
|
469 |
|
470 return NS_OK; |
|
471 } |
|
472 |
|
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; |
|
484 |
|
485 while (aLength) { |
|
486 size = std::min<uint32_t>(aLength, sizeof(buf)); |
|
487 |
|
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 } |
|
501 |
|
502 aLength -= amt; |
|
503 } |
|
504 return NS_OK; |
|
505 } |
|
506 |
|
507 NS_IMETHODIMP |
|
508 InputTestConsumer::OnStopRequest(nsIRequest *request, nsISupports* context, |
|
509 nsresult aStatus) |
|
510 { |
|
511 LOG(("InputTestConsumer::OnStopRequest [status=%x]\n", aStatus)); |
|
512 |
|
513 URLLoadInfo* info = (URLLoadInfo*)context; |
|
514 |
|
515 if (info) { |
|
516 uint32_t httpStatus; |
|
517 bool bHTTPURL = false; |
|
518 |
|
519 info->mTotalTime = PR_Now() - info->mTotalTime; |
|
520 |
|
521 double readTime = ((info->mTotalTime-info->mConnectTime)/1000.0)/1000.0; |
|
522 |
|
523 nsCOMPtr<nsIHttpChannel> pHTTPCon(do_QueryInterface(request)); |
|
524 if (pHTTPCon) { |
|
525 pHTTPCon->GetResponseStatus(&httpStatus); |
|
526 bHTTPURL = true; |
|
527 } |
|
528 |
|
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 } |
|
546 |
|
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 } |
|
553 |
|
554 if (--gKeepRunning == 0) |
|
555 QuitPumpingEvents(); |
|
556 return NS_OK; |
|
557 } |
|
558 |
|
559 //----------------------------------------------------------------------------- |
|
560 // NotificationCallbacks |
|
561 //----------------------------------------------------------------------------- |
|
562 |
|
563 class NotificationCallbacks MOZ_FINAL : public nsIInterfaceRequestor { |
|
564 public: |
|
565 NS_DECL_ISUPPORTS |
|
566 |
|
567 NotificationCallbacks() { |
|
568 } |
|
569 |
|
570 NS_IMETHOD GetInterface(const nsIID& iid, void* *result) { |
|
571 nsresult rv = NS_ERROR_FAILURE; |
|
572 |
|
573 if (iid.Equals(NS_GET_IID(nsIChannelEventSink))) { |
|
574 TestChannelEventSink *sink; |
|
575 |
|
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 } |
|
583 |
|
584 if (iid.Equals(NS_GET_IID(nsIAuthPrompt))) { |
|
585 TestAuthPrompt *prompt; |
|
586 |
|
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 }; |
|
597 |
|
598 NS_IMPL_ISUPPORTS(NotificationCallbacks, nsIInterfaceRequestor) |
|
599 |
|
600 //----------------------------------------------------------------------------- |
|
601 // helpers... |
|
602 //----------------------------------------------------------------------------- |
|
603 |
|
604 nsresult StartLoadingURL(const char* aUrlString) |
|
605 { |
|
606 nsresult rv; |
|
607 |
|
608 nsCOMPtr<nsIIOService> pService(do_GetService(kIOServiceCID, &rv)); |
|
609 if (pService) { |
|
610 nsCOMPtr<nsIURI> pURL; |
|
611 |
|
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; |
|
618 |
|
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); |
|
625 |
|
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 } |
|
635 |
|
636 nsCOMPtr<nsITimedChannel> timed(do_QueryInterface(pChannel)); |
|
637 if (timed) |
|
638 timed->SetTimingEnabled(true); |
|
639 |
|
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 } |
|
648 |
|
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)); |
|
655 |
|
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; |
|
664 |
|
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 } |
|
671 |
|
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 } |
|
679 |
|
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); |
|
694 |
|
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 } |
|
704 |
|
705 return rv; |
|
706 } |
|
707 |
|
708 static int32_t |
|
709 FindChar(nsCString& buffer, char c) |
|
710 { |
|
711 const char *b; |
|
712 int32_t len = NS_CStringGetData(buffer, &b); |
|
713 |
|
714 for (int32_t offset = 0; offset < len; ++offset) { |
|
715 if (b[offset] == c) |
|
716 return offset; |
|
717 } |
|
718 |
|
719 return -1; |
|
720 } |
|
721 |
|
722 |
|
723 static void |
|
724 StripChar(nsCString& buffer, char c) |
|
725 { |
|
726 const char *b; |
|
727 uint32_t len = NS_CStringGetData(buffer, &b) - 1; |
|
728 |
|
729 for (; len > 0; --len) { |
|
730 if (b[len] == c) { |
|
731 buffer.Cut(len, 1); |
|
732 NS_CStringGetData(buffer, &b); |
|
733 } |
|
734 } |
|
735 } |
|
736 |
|
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; |
|
745 |
|
746 fd = PR_Open(aFileName, PR_RDONLY, 777); |
|
747 if (!fd) { |
|
748 return NS_ERROR_FAILURE; |
|
749 } |
|
750 |
|
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); |
|
760 |
|
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); |
|
775 |
|
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 } |
|
782 |
|
783 PR_Close(fd); |
|
784 return NS_OK; |
|
785 } |
|
786 |
|
787 |
|
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 } |
|
799 |
|
800 } // namespace |
|
801 |
|
802 using namespace TestProtocols; |
|
803 |
|
804 int |
|
805 main(int argc, char* argv[]) |
|
806 { |
|
807 if (test_common_init(&argc, &argv) != 0) |
|
808 return -1; |
|
809 |
|
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 } |
|
817 |
|
818 #if defined(PR_LOGGING) |
|
819 gTestLog = PR_NewLogModule("Test"); |
|
820 #endif |
|
821 |
|
822 /* |
|
823 The following code only deals with XPCOM registration stuff. and setting |
|
824 up the event queues. Copied from TestSocketIO.cpp |
|
825 */ |
|
826 |
|
827 rv = NS_InitXPCOM2(nullptr, nullptr, nullptr); |
|
828 if (NS_FAILED(rv)) return -1; |
|
829 |
|
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 } |
|
839 |
|
840 // Turn on netlib tracing... |
|
841 if (PL_strcasecmp(argv[i], "-file") == 0) { |
|
842 LoadURLsFromFile(argv[++i]); |
|
843 continue; |
|
844 } |
|
845 |
|
846 if (PL_strcasecmp(argv[i], "-console") == 0) { |
|
847 gAskUserForInput = true; |
|
848 continue; |
|
849 } |
|
850 |
|
851 if (PL_strcasecmp(argv[i], "-resume") == 0) { |
|
852 gResume = true; |
|
853 PR_sscanf(argv[++i], "%llu", &gStartAt); |
|
854 continue; |
|
855 } |
|
856 |
|
857 if (PL_strcasecmp(argv[i], "-entityid") == 0) { |
|
858 gEntityID = argv[++i]; |
|
859 continue; |
|
860 } |
|
861 |
|
862 if (PL_strcasecmp(argv[i], "-proxy") == 0) { |
|
863 SetHttpProxy(argv[++i]); |
|
864 continue; |
|
865 } |
|
866 |
|
867 if (PL_strcasecmp(argv[i], "-pac") == 0) { |
|
868 SetPACFile(argv[++i]); |
|
869 continue; |
|
870 } |
|
871 |
|
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 } |