|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
|
2 /* vim:set ts=4 sw=4 cindent et: */ |
|
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 #include "mozilla/DebugOnly.h" |
|
8 |
|
9 #include "nsIOService.h" |
|
10 #include "nsIProtocolHandler.h" |
|
11 #include "nsIFileProtocolHandler.h" |
|
12 #include "nscore.h" |
|
13 #include "nsIURI.h" |
|
14 #include "prprf.h" |
|
15 #include "nsIErrorService.h" |
|
16 #include "netCore.h" |
|
17 #include "nsIObserverService.h" |
|
18 #include "nsIPrefService.h" |
|
19 #include "nsXPCOM.h" |
|
20 #include "nsIProxiedProtocolHandler.h" |
|
21 #include "nsIProxyInfo.h" |
|
22 #include "nsEscape.h" |
|
23 #include "nsNetCID.h" |
|
24 #include "nsCRT.h" |
|
25 #include "nsSimpleNestedURI.h" |
|
26 #include "nsNetUtil.h" |
|
27 #include "nsTArray.h" |
|
28 #include "nsIConsoleService.h" |
|
29 #include "nsIUploadChannel2.h" |
|
30 #include "nsXULAppAPI.h" |
|
31 #include "nsIProtocolProxyCallback.h" |
|
32 #include "nsICancelable.h" |
|
33 #include "nsINetworkLinkService.h" |
|
34 #include "nsPISocketTransportService.h" |
|
35 #include "nsAsyncRedirectVerifyHelper.h" |
|
36 #include "nsURLHelper.h" |
|
37 #include "nsPIDNSService.h" |
|
38 #include "nsIProtocolProxyService2.h" |
|
39 #include "MainThreadUtils.h" |
|
40 |
|
41 #if defined(XP_WIN) |
|
42 #include "nsNativeConnectionHelper.h" |
|
43 #endif |
|
44 |
|
45 using namespace mozilla; |
|
46 |
|
47 #define PORT_PREF_PREFIX "network.security.ports." |
|
48 #define PORT_PREF(x) PORT_PREF_PREFIX x |
|
49 #define AUTODIAL_PREF "network.autodial-helper.enabled" |
|
50 #define MANAGE_OFFLINE_STATUS_PREF "network.manage-offline-status" |
|
51 |
|
52 // Nb: these have been misnomers since bug 715770 removed the buffer cache. |
|
53 // "network.segment.count" and "network.segment.size" would be better names, |
|
54 // but the old names are still used to preserve backward compatibility. |
|
55 #define NECKO_BUFFER_CACHE_COUNT_PREF "network.buffer.cache.count" |
|
56 #define NECKO_BUFFER_CACHE_SIZE_PREF "network.buffer.cache.size" |
|
57 |
|
58 #define MAX_RECURSION_COUNT 50 |
|
59 |
|
60 nsIOService* gIOService = nullptr; |
|
61 static bool gHasWarnedUploadChannel2; |
|
62 |
|
63 // A general port blacklist. Connections to these ports will not be allowed unless |
|
64 // the protocol overrides. |
|
65 // |
|
66 // TODO: I am sure that there are more ports to be added. |
|
67 // This cut is based on the classic mozilla codebase |
|
68 |
|
69 int16_t gBadPortList[] = { |
|
70 1, // tcpmux |
|
71 7, // echo |
|
72 9, // discard |
|
73 11, // systat |
|
74 13, // daytime |
|
75 15, // netstat |
|
76 17, // qotd |
|
77 19, // chargen |
|
78 20, // ftp-data |
|
79 21, // ftp-cntl |
|
80 22, // ssh |
|
81 23, // telnet |
|
82 25, // smtp |
|
83 37, // time |
|
84 42, // name |
|
85 43, // nicname |
|
86 53, // domain |
|
87 77, // priv-rjs |
|
88 79, // finger |
|
89 87, // ttylink |
|
90 95, // supdup |
|
91 101, // hostriame |
|
92 102, // iso-tsap |
|
93 103, // gppitnp |
|
94 104, // acr-nema |
|
95 109, // pop2 |
|
96 110, // pop3 |
|
97 111, // sunrpc |
|
98 113, // auth |
|
99 115, // sftp |
|
100 117, // uucp-path |
|
101 119, // nntp |
|
102 123, // NTP |
|
103 135, // loc-srv / epmap |
|
104 139, // netbios |
|
105 143, // imap2 |
|
106 179, // BGP |
|
107 389, // ldap |
|
108 465, // smtp+ssl |
|
109 512, // print / exec |
|
110 513, // login |
|
111 514, // shell |
|
112 515, // printer |
|
113 526, // tempo |
|
114 530, // courier |
|
115 531, // Chat |
|
116 532, // netnews |
|
117 540, // uucp |
|
118 556, // remotefs |
|
119 563, // nntp+ssl |
|
120 587, // |
|
121 601, // |
|
122 636, // ldap+ssl |
|
123 993, // imap+ssl |
|
124 995, // pop3+ssl |
|
125 2049, // nfs |
|
126 4045, // lockd |
|
127 6000, // x11 |
|
128 0, // This MUST be zero so that we can populating the array |
|
129 }; |
|
130 |
|
131 static const char kProfileChangeNetTeardownTopic[] = "profile-change-net-teardown"; |
|
132 static const char kProfileChangeNetRestoreTopic[] = "profile-change-net-restore"; |
|
133 static const char kProfileDoChange[] = "profile-do-change"; |
|
134 |
|
135 // Necko buffer defaults |
|
136 uint32_t nsIOService::gDefaultSegmentSize = 4096; |
|
137 uint32_t nsIOService::gDefaultSegmentCount = 24; |
|
138 |
|
139 //////////////////////////////////////////////////////////////////////////////// |
|
140 |
|
141 nsIOService::nsIOService() |
|
142 : mOffline(true) |
|
143 , mOfflineForProfileChange(false) |
|
144 , mManageOfflineStatus(false) |
|
145 , mSettingOffline(false) |
|
146 , mSetOfflineValue(false) |
|
147 , mShutdown(false) |
|
148 , mNetworkLinkServiceInitialized(false) |
|
149 , mChannelEventSinks(NS_CHANNEL_EVENT_SINK_CATEGORY) |
|
150 , mAutoDialEnabled(false) |
|
151 { |
|
152 } |
|
153 |
|
154 nsresult |
|
155 nsIOService::Init() |
|
156 { |
|
157 nsresult rv; |
|
158 |
|
159 // We need to get references to the DNS service so that we can shut it |
|
160 // down later. If we wait until the nsIOService is being shut down, |
|
161 // GetService will fail at that point. |
|
162 |
|
163 mDNSService = do_GetService(NS_DNSSERVICE_CONTRACTID, &rv); |
|
164 if (NS_FAILED(rv)) { |
|
165 NS_WARNING("failed to get DNS service"); |
|
166 return rv; |
|
167 } |
|
168 |
|
169 // XXX hack until xpidl supports error info directly (bug 13423) |
|
170 nsCOMPtr<nsIErrorService> errorService = do_GetService(NS_ERRORSERVICE_CONTRACTID); |
|
171 if (errorService) { |
|
172 errorService->RegisterErrorStringBundle(NS_ERROR_MODULE_NETWORK, NECKO_MSGS_URL); |
|
173 } |
|
174 else |
|
175 NS_WARNING("failed to get error service"); |
|
176 |
|
177 // setup our bad port list stuff |
|
178 for(int i=0; gBadPortList[i]; i++) |
|
179 mRestrictedPortList.AppendElement(gBadPortList[i]); |
|
180 |
|
181 // Further modifications to the port list come from prefs |
|
182 nsCOMPtr<nsIPrefBranch> prefBranch; |
|
183 GetPrefBranch(getter_AddRefs(prefBranch)); |
|
184 if (prefBranch) { |
|
185 prefBranch->AddObserver(PORT_PREF_PREFIX, this, true); |
|
186 prefBranch->AddObserver(AUTODIAL_PREF, this, true); |
|
187 prefBranch->AddObserver(MANAGE_OFFLINE_STATUS_PREF, this, true); |
|
188 prefBranch->AddObserver(NECKO_BUFFER_CACHE_COUNT_PREF, this, true); |
|
189 prefBranch->AddObserver(NECKO_BUFFER_CACHE_SIZE_PREF, this, true); |
|
190 PrefsChanged(prefBranch); |
|
191 } |
|
192 |
|
193 // Register for profile change notifications |
|
194 nsCOMPtr<nsIObserverService> observerService = |
|
195 mozilla::services::GetObserverService(); |
|
196 if (observerService) { |
|
197 observerService->AddObserver(this, kProfileChangeNetTeardownTopic, true); |
|
198 observerService->AddObserver(this, kProfileChangeNetRestoreTopic, true); |
|
199 observerService->AddObserver(this, kProfileDoChange, true); |
|
200 observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, true); |
|
201 observerService->AddObserver(this, NS_NETWORK_LINK_TOPIC, true); |
|
202 } |
|
203 else |
|
204 NS_WARNING("failed to get observer service"); |
|
205 |
|
206 gIOService = this; |
|
207 |
|
208 InitializeNetworkLinkService(); |
|
209 |
|
210 return NS_OK; |
|
211 } |
|
212 |
|
213 |
|
214 nsIOService::~nsIOService() |
|
215 { |
|
216 gIOService = nullptr; |
|
217 } |
|
218 |
|
219 nsresult |
|
220 nsIOService::InitializeSocketTransportService() |
|
221 { |
|
222 nsresult rv = NS_OK; |
|
223 |
|
224 if (!mSocketTransportService) { |
|
225 mSocketTransportService = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); |
|
226 if (NS_FAILED(rv)) { |
|
227 NS_WARNING("failed to get socket transport service"); |
|
228 } |
|
229 } |
|
230 |
|
231 if (mSocketTransportService) { |
|
232 rv = mSocketTransportService->Init(); |
|
233 NS_ASSERTION(NS_SUCCEEDED(rv), "socket transport service init failed"); |
|
234 mSocketTransportService->SetAutodialEnabled(mAutoDialEnabled); |
|
235 mSocketTransportService->SetOffline(false); |
|
236 } |
|
237 |
|
238 return rv; |
|
239 } |
|
240 |
|
241 nsresult |
|
242 nsIOService::InitializeNetworkLinkService() |
|
243 { |
|
244 nsresult rv = NS_OK; |
|
245 |
|
246 if (mNetworkLinkServiceInitialized) |
|
247 return rv; |
|
248 |
|
249 if (!NS_IsMainThread()) { |
|
250 NS_WARNING("Network link service should be created on main thread"); |
|
251 return NS_ERROR_FAILURE; |
|
252 } |
|
253 |
|
254 // go into managed mode if we can, and chrome process |
|
255 if (XRE_GetProcessType() == GeckoProcessType_Default) |
|
256 { |
|
257 mNetworkLinkService = do_GetService(NS_NETWORK_LINK_SERVICE_CONTRACTID, &rv); |
|
258 } |
|
259 |
|
260 if (mNetworkLinkService) { |
|
261 mNetworkLinkServiceInitialized = true; |
|
262 } |
|
263 else { |
|
264 // We can't really determine if the machine has a usable network connection, |
|
265 // so let's cross our fingers! |
|
266 mManageOfflineStatus = false; |
|
267 } |
|
268 |
|
269 |
|
270 if (mManageOfflineStatus) |
|
271 TrackNetworkLinkStatusForOffline(); |
|
272 else |
|
273 SetOffline(false); |
|
274 |
|
275 return rv; |
|
276 } |
|
277 |
|
278 nsIOService* |
|
279 nsIOService::GetInstance() { |
|
280 if (!gIOService) { |
|
281 gIOService = new nsIOService(); |
|
282 if (!gIOService) |
|
283 return nullptr; |
|
284 NS_ADDREF(gIOService); |
|
285 |
|
286 nsresult rv = gIOService->Init(); |
|
287 if (NS_FAILED(rv)) { |
|
288 NS_RELEASE(gIOService); |
|
289 return nullptr; |
|
290 } |
|
291 return gIOService; |
|
292 } |
|
293 NS_ADDREF(gIOService); |
|
294 return gIOService; |
|
295 } |
|
296 |
|
297 NS_IMPL_ISUPPORTS(nsIOService, |
|
298 nsIIOService, |
|
299 nsIIOService2, |
|
300 nsINetUtil, |
|
301 nsISpeculativeConnect, |
|
302 nsIObserver, |
|
303 nsISupportsWeakReference) |
|
304 |
|
305 //////////////////////////////////////////////////////////////////////////////// |
|
306 |
|
307 nsresult |
|
308 nsIOService::AsyncOnChannelRedirect(nsIChannel* oldChan, nsIChannel* newChan, |
|
309 uint32_t flags, |
|
310 nsAsyncRedirectVerifyHelper *helper) |
|
311 { |
|
312 nsCOMPtr<nsIChannelEventSink> sink = |
|
313 do_GetService(NS_GLOBAL_CHANNELEVENTSINK_CONTRACTID); |
|
314 if (sink) { |
|
315 nsresult rv = helper->DelegateOnChannelRedirect(sink, oldChan, |
|
316 newChan, flags); |
|
317 if (NS_FAILED(rv)) |
|
318 return rv; |
|
319 } |
|
320 |
|
321 // Finally, our category |
|
322 nsCOMArray<nsIChannelEventSink> entries; |
|
323 mChannelEventSinks.GetEntries(entries); |
|
324 int32_t len = entries.Count(); |
|
325 for (int32_t i = 0; i < len; ++i) { |
|
326 nsresult rv = helper->DelegateOnChannelRedirect(entries[i], oldChan, |
|
327 newChan, flags); |
|
328 if (NS_FAILED(rv)) |
|
329 return rv; |
|
330 } |
|
331 return NS_OK; |
|
332 } |
|
333 |
|
334 nsresult |
|
335 nsIOService::CacheProtocolHandler(const char *scheme, nsIProtocolHandler *handler) |
|
336 { |
|
337 for (unsigned int i=0; i<NS_N(gScheme); i++) |
|
338 { |
|
339 if (!nsCRT::strcasecmp(scheme, gScheme[i])) |
|
340 { |
|
341 nsresult rv; |
|
342 NS_ASSERTION(!mWeakHandler[i], "Protocol handler already cached"); |
|
343 // Make sure the handler supports weak references. |
|
344 nsCOMPtr<nsISupportsWeakReference> factoryPtr = do_QueryInterface(handler, &rv); |
|
345 if (!factoryPtr) |
|
346 { |
|
347 // Don't cache handlers that don't support weak reference as |
|
348 // there is real danger of a circular reference. |
|
349 #ifdef DEBUG_dp |
|
350 printf("DEBUG: %s protcol handler doesn't support weak ref. Not cached.\n", scheme); |
|
351 #endif /* DEBUG_dp */ |
|
352 return NS_ERROR_FAILURE; |
|
353 } |
|
354 mWeakHandler[i] = do_GetWeakReference(handler); |
|
355 return NS_OK; |
|
356 } |
|
357 } |
|
358 return NS_ERROR_FAILURE; |
|
359 } |
|
360 |
|
361 nsresult |
|
362 nsIOService::GetCachedProtocolHandler(const char *scheme, nsIProtocolHandler **result, uint32_t start, uint32_t end) |
|
363 { |
|
364 uint32_t len = end - start - 1; |
|
365 for (unsigned int i=0; i<NS_N(gScheme); i++) |
|
366 { |
|
367 if (!mWeakHandler[i]) |
|
368 continue; |
|
369 |
|
370 // handle unterminated strings |
|
371 // start is inclusive, end is exclusive, len = end - start - 1 |
|
372 if (end ? (!nsCRT::strncasecmp(scheme + start, gScheme[i], len) |
|
373 && gScheme[i][len] == '\0') |
|
374 : (!nsCRT::strcasecmp(scheme, gScheme[i]))) |
|
375 { |
|
376 return CallQueryReferent(mWeakHandler[i].get(), result); |
|
377 } |
|
378 } |
|
379 return NS_ERROR_FAILURE; |
|
380 } |
|
381 |
|
382 NS_IMETHODIMP |
|
383 nsIOService::GetProtocolHandler(const char* scheme, nsIProtocolHandler* *result) |
|
384 { |
|
385 nsresult rv; |
|
386 |
|
387 NS_ENSURE_ARG_POINTER(scheme); |
|
388 // XXX we may want to speed this up by introducing our own protocol |
|
389 // scheme -> protocol handler mapping, avoiding the string manipulation |
|
390 // and service manager stuff |
|
391 |
|
392 rv = GetCachedProtocolHandler(scheme, result); |
|
393 if (NS_SUCCEEDED(rv)) |
|
394 return rv; |
|
395 |
|
396 bool externalProtocol = false; |
|
397 nsCOMPtr<nsIPrefBranch> prefBranch; |
|
398 GetPrefBranch(getter_AddRefs(prefBranch)); |
|
399 if (prefBranch) { |
|
400 nsAutoCString externalProtocolPref("network.protocol-handler.external."); |
|
401 externalProtocolPref += scheme; |
|
402 rv = prefBranch->GetBoolPref(externalProtocolPref.get(), &externalProtocol); |
|
403 if (NS_FAILED(rv)) { |
|
404 externalProtocol = false; |
|
405 } |
|
406 } |
|
407 |
|
408 if (!externalProtocol) { |
|
409 nsAutoCString contractID(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX); |
|
410 contractID += scheme; |
|
411 ToLowerCase(contractID); |
|
412 |
|
413 rv = CallGetService(contractID.get(), result); |
|
414 if (NS_SUCCEEDED(rv)) { |
|
415 CacheProtocolHandler(scheme, *result); |
|
416 return rv; |
|
417 } |
|
418 |
|
419 #ifdef MOZ_X11 |
|
420 // check to see whether GVFS can handle this URI scheme. if it can |
|
421 // create a nsIURI for the "scheme:", then we assume it has support for |
|
422 // the requested protocol. otherwise, we failover to using the default |
|
423 // protocol handler. |
|
424 |
|
425 rv = CallGetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX"moz-gio", |
|
426 result); |
|
427 if (NS_SUCCEEDED(rv)) { |
|
428 nsAutoCString spec(scheme); |
|
429 spec.Append(':'); |
|
430 |
|
431 nsIURI *uri; |
|
432 rv = (*result)->NewURI(spec, nullptr, nullptr, &uri); |
|
433 if (NS_SUCCEEDED(rv)) { |
|
434 NS_RELEASE(uri); |
|
435 return rv; |
|
436 } |
|
437 |
|
438 NS_RELEASE(*result); |
|
439 } |
|
440 |
|
441 // check to see whether GnomeVFS can handle this URI scheme. if it can |
|
442 // create a nsIURI for the "scheme:", then we assume it has support for |
|
443 // the requested protocol. otherwise, we failover to using the default |
|
444 // protocol handler. |
|
445 |
|
446 // XXX should this be generalized into something that searches a |
|
447 // category? (see bug 234714) |
|
448 |
|
449 rv = CallGetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX"moz-gnomevfs", |
|
450 result); |
|
451 if (NS_SUCCEEDED(rv)) { |
|
452 nsAutoCString spec(scheme); |
|
453 spec.Append(':'); |
|
454 |
|
455 nsIURI *uri; |
|
456 rv = (*result)->NewURI(spec, nullptr, nullptr, &uri); |
|
457 if (NS_SUCCEEDED(rv)) { |
|
458 NS_RELEASE(uri); |
|
459 return rv; |
|
460 } |
|
461 |
|
462 NS_RELEASE(*result); |
|
463 } |
|
464 #endif |
|
465 } |
|
466 |
|
467 // Okay we don't have a protocol handler to handle this url type, so use |
|
468 // the default protocol handler. This will cause urls to get dispatched |
|
469 // out to the OS ('cause we can't do anything with them) when we try to |
|
470 // read from a channel created by the default protocol handler. |
|
471 |
|
472 rv = CallGetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX"default", |
|
473 result); |
|
474 if (NS_FAILED(rv)) |
|
475 return NS_ERROR_UNKNOWN_PROTOCOL; |
|
476 |
|
477 return rv; |
|
478 } |
|
479 |
|
480 NS_IMETHODIMP |
|
481 nsIOService::ExtractScheme(const nsACString &inURI, nsACString &scheme) |
|
482 { |
|
483 return net_ExtractURLScheme(inURI, nullptr, nullptr, &scheme); |
|
484 } |
|
485 |
|
486 NS_IMETHODIMP |
|
487 nsIOService::GetProtocolFlags(const char* scheme, uint32_t *flags) |
|
488 { |
|
489 nsCOMPtr<nsIProtocolHandler> handler; |
|
490 nsresult rv = GetProtocolHandler(scheme, getter_AddRefs(handler)); |
|
491 if (NS_FAILED(rv)) return rv; |
|
492 |
|
493 rv = handler->GetProtocolFlags(flags); |
|
494 return rv; |
|
495 } |
|
496 |
|
497 class AutoIncrement |
|
498 { |
|
499 public: |
|
500 AutoIncrement(uint32_t *var) : mVar(var) |
|
501 { |
|
502 ++*var; |
|
503 } |
|
504 ~AutoIncrement() |
|
505 { |
|
506 --*mVar; |
|
507 } |
|
508 private: |
|
509 uint32_t *mVar; |
|
510 }; |
|
511 |
|
512 nsresult |
|
513 nsIOService::NewURI(const nsACString &aSpec, const char *aCharset, nsIURI *aBaseURI, nsIURI **result) |
|
514 { |
|
515 NS_ASSERTION(NS_IsMainThread(), "wrong thread"); |
|
516 |
|
517 static uint32_t recursionCount = 0; |
|
518 if (recursionCount >= MAX_RECURSION_COUNT) |
|
519 return NS_ERROR_MALFORMED_URI; |
|
520 AutoIncrement inc(&recursionCount); |
|
521 |
|
522 nsAutoCString scheme; |
|
523 nsresult rv = ExtractScheme(aSpec, scheme); |
|
524 if (NS_FAILED(rv)) { |
|
525 // then aSpec is relative |
|
526 if (!aBaseURI) |
|
527 return NS_ERROR_MALFORMED_URI; |
|
528 |
|
529 rv = aBaseURI->GetScheme(scheme); |
|
530 if (NS_FAILED(rv)) return rv; |
|
531 } |
|
532 |
|
533 // now get the handler for this scheme |
|
534 nsCOMPtr<nsIProtocolHandler> handler; |
|
535 rv = GetProtocolHandler(scheme.get(), getter_AddRefs(handler)); |
|
536 if (NS_FAILED(rv)) return rv; |
|
537 |
|
538 return handler->NewURI(aSpec, aCharset, aBaseURI, result); |
|
539 } |
|
540 |
|
541 |
|
542 NS_IMETHODIMP |
|
543 nsIOService::NewFileURI(nsIFile *file, nsIURI **result) |
|
544 { |
|
545 nsresult rv; |
|
546 NS_ENSURE_ARG_POINTER(file); |
|
547 |
|
548 nsCOMPtr<nsIProtocolHandler> handler; |
|
549 |
|
550 rv = GetProtocolHandler("file", getter_AddRefs(handler)); |
|
551 if (NS_FAILED(rv)) return rv; |
|
552 |
|
553 nsCOMPtr<nsIFileProtocolHandler> fileHandler( do_QueryInterface(handler, &rv) ); |
|
554 if (NS_FAILED(rv)) return rv; |
|
555 |
|
556 return fileHandler->NewFileURI(file, result); |
|
557 } |
|
558 |
|
559 NS_IMETHODIMP |
|
560 nsIOService::NewChannelFromURI(nsIURI *aURI, nsIChannel **result) |
|
561 { |
|
562 return NewChannelFromURIWithProxyFlags(aURI, nullptr, 0, result); |
|
563 } |
|
564 |
|
565 NS_IMETHODIMP |
|
566 nsIOService::NewChannelFromURIWithProxyFlags(nsIURI *aURI, |
|
567 nsIURI *aProxyURI, |
|
568 uint32_t aProxyFlags, |
|
569 nsIChannel **result) |
|
570 { |
|
571 nsresult rv; |
|
572 NS_ENSURE_ARG_POINTER(aURI); |
|
573 |
|
574 nsAutoCString scheme; |
|
575 rv = aURI->GetScheme(scheme); |
|
576 if (NS_FAILED(rv)) |
|
577 return rv; |
|
578 |
|
579 nsCOMPtr<nsIProtocolHandler> handler; |
|
580 rv = GetProtocolHandler(scheme.get(), getter_AddRefs(handler)); |
|
581 if (NS_FAILED(rv)) |
|
582 return rv; |
|
583 |
|
584 uint32_t protoFlags; |
|
585 rv = handler->GetProtocolFlags(&protoFlags); |
|
586 if (NS_FAILED(rv)) |
|
587 return rv; |
|
588 |
|
589 nsCOMPtr<nsIProxiedProtocolHandler> pph = do_QueryInterface(handler); |
|
590 if (pph) |
|
591 rv = pph->NewProxiedChannel(aURI, nullptr, aProxyFlags, aProxyURI, result); |
|
592 else |
|
593 rv = handler->NewChannel(aURI, result); |
|
594 NS_ENSURE_SUCCESS(rv, rv); |
|
595 |
|
596 // Some extensions override the http protocol handler and provide their own |
|
597 // implementation. The channels returned from that implementation doesn't |
|
598 // seem to always implement the nsIUploadChannel2 interface, presumably |
|
599 // because it's a new interface. |
|
600 // Eventually we should remove this and simply require that http channels |
|
601 // implement the new interface. |
|
602 // See bug 529041 |
|
603 if (!gHasWarnedUploadChannel2 && scheme.EqualsLiteral("http")) { |
|
604 nsCOMPtr<nsIUploadChannel2> uploadChannel2 = do_QueryInterface(*result); |
|
605 if (!uploadChannel2) { |
|
606 nsCOMPtr<nsIConsoleService> consoleService = |
|
607 do_GetService(NS_CONSOLESERVICE_CONTRACTID); |
|
608 if (consoleService) { |
|
609 consoleService->LogStringMessage(NS_LITERAL_STRING( |
|
610 "Http channel implementation doesn't support nsIUploadChannel2. An extension has supplied a non-functional http protocol handler. This will break behavior and in future releases not work at all." |
|
611 ).get()); |
|
612 } |
|
613 gHasWarnedUploadChannel2 = true; |
|
614 } |
|
615 } |
|
616 |
|
617 return NS_OK; |
|
618 } |
|
619 |
|
620 NS_IMETHODIMP |
|
621 nsIOService::NewChannel(const nsACString &aSpec, const char *aCharset, nsIURI *aBaseURI, nsIChannel **result) |
|
622 { |
|
623 nsresult rv; |
|
624 nsCOMPtr<nsIURI> uri; |
|
625 rv = NewURI(aSpec, aCharset, aBaseURI, getter_AddRefs(uri)); |
|
626 if (NS_FAILED(rv)) return rv; |
|
627 |
|
628 return NewChannelFromURI(uri, result); |
|
629 } |
|
630 |
|
631 bool |
|
632 nsIOService::IsLinkUp() |
|
633 { |
|
634 InitializeNetworkLinkService(); |
|
635 |
|
636 if (!mNetworkLinkService) { |
|
637 // We cannot decide, assume the link is up |
|
638 return true; |
|
639 } |
|
640 |
|
641 bool isLinkUp; |
|
642 nsresult rv; |
|
643 rv = mNetworkLinkService->GetIsLinkUp(&isLinkUp); |
|
644 if (NS_FAILED(rv)) { |
|
645 return true; |
|
646 } |
|
647 |
|
648 return isLinkUp; |
|
649 } |
|
650 |
|
651 NS_IMETHODIMP |
|
652 nsIOService::GetOffline(bool *offline) |
|
653 { |
|
654 *offline = mOffline; |
|
655 return NS_OK; |
|
656 } |
|
657 |
|
658 NS_IMETHODIMP |
|
659 nsIOService::SetOffline(bool offline) |
|
660 { |
|
661 // When someone wants to go online (!offline) after we got XPCOM shutdown |
|
662 // throw ERROR_NOT_AVAILABLE to prevent return to online state. |
|
663 if ((mShutdown || mOfflineForProfileChange) && !offline) |
|
664 return NS_ERROR_NOT_AVAILABLE; |
|
665 |
|
666 // SetOffline() may re-enter while it's shutting down services. |
|
667 // If that happens, save the most recent value and it will be |
|
668 // processed when the first SetOffline() call is done bringing |
|
669 // down the service. |
|
670 mSetOfflineValue = offline; |
|
671 if (mSettingOffline) { |
|
672 return NS_OK; |
|
673 } |
|
674 |
|
675 mSettingOffline = true; |
|
676 |
|
677 nsCOMPtr<nsIObserverService> observerService = |
|
678 mozilla::services::GetObserverService(); |
|
679 |
|
680 NS_ASSERTION(observerService, "The observer service should not be null"); |
|
681 |
|
682 if (XRE_GetProcessType() == GeckoProcessType_Default) { |
|
683 if (observerService) { |
|
684 (void)observerService->NotifyObservers(nullptr, |
|
685 NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC, offline ? |
|
686 MOZ_UTF16("true") : |
|
687 MOZ_UTF16("false")); |
|
688 } |
|
689 } |
|
690 |
|
691 nsIIOService *subject = static_cast<nsIIOService *>(this); |
|
692 while (mSetOfflineValue != mOffline) { |
|
693 offline = mSetOfflineValue; |
|
694 |
|
695 if (offline && !mOffline) { |
|
696 NS_NAMED_LITERAL_STRING(offlineString, NS_IOSERVICE_OFFLINE); |
|
697 mOffline = true; // indicate we're trying to shutdown |
|
698 |
|
699 // don't care if notifications fail |
|
700 if (observerService) |
|
701 observerService->NotifyObservers(subject, |
|
702 NS_IOSERVICE_GOING_OFFLINE_TOPIC, |
|
703 offlineString.get()); |
|
704 |
|
705 if (mDNSService) |
|
706 mDNSService->SetOffline(true); |
|
707 |
|
708 if (mSocketTransportService) |
|
709 mSocketTransportService->SetOffline(true); |
|
710 |
|
711 if (observerService) |
|
712 observerService->NotifyObservers(subject, |
|
713 NS_IOSERVICE_OFFLINE_STATUS_TOPIC, |
|
714 offlineString.get()); |
|
715 } |
|
716 else if (!offline && mOffline) { |
|
717 // go online |
|
718 if (mDNSService) { |
|
719 mDNSService->SetOffline(false); |
|
720 DebugOnly<nsresult> rv = mDNSService->Init(); |
|
721 NS_ASSERTION(NS_SUCCEEDED(rv), "DNS service init failed"); |
|
722 } |
|
723 InitializeSocketTransportService(); |
|
724 mOffline = false; // indicate success only AFTER we've |
|
725 // brought up the services |
|
726 |
|
727 // trigger a PAC reload when we come back online |
|
728 if (mProxyService) |
|
729 mProxyService->ReloadPAC(); |
|
730 |
|
731 // don't care if notification fails |
|
732 if (observerService) |
|
733 observerService->NotifyObservers(subject, |
|
734 NS_IOSERVICE_OFFLINE_STATUS_TOPIC, |
|
735 NS_LITERAL_STRING(NS_IOSERVICE_ONLINE).get()); |
|
736 } |
|
737 } |
|
738 |
|
739 // Don't notify here, as the above notifications (if used) suffice. |
|
740 if ((mShutdown || mOfflineForProfileChange) && mOffline) { |
|
741 // be sure to try and shutdown both (even if the first fails)... |
|
742 // shutdown dns service first, because it has callbacks for socket transport |
|
743 if (mDNSService) { |
|
744 DebugOnly<nsresult> rv = mDNSService->Shutdown(); |
|
745 NS_ASSERTION(NS_SUCCEEDED(rv), "DNS service shutdown failed"); |
|
746 } |
|
747 if (mSocketTransportService) { |
|
748 DebugOnly<nsresult> rv = mSocketTransportService->Shutdown(); |
|
749 NS_ASSERTION(NS_SUCCEEDED(rv), "socket transport service shutdown failed"); |
|
750 } |
|
751 } |
|
752 |
|
753 mSettingOffline = false; |
|
754 |
|
755 return NS_OK; |
|
756 } |
|
757 |
|
758 |
|
759 NS_IMETHODIMP |
|
760 nsIOService::AllowPort(int32_t inPort, const char *scheme, bool *_retval) |
|
761 { |
|
762 int16_t port = inPort; |
|
763 if (port == -1) { |
|
764 *_retval = true; |
|
765 return NS_OK; |
|
766 } |
|
767 |
|
768 if (port == 0) { |
|
769 *_retval = false; |
|
770 return NS_OK; |
|
771 } |
|
772 |
|
773 // first check to see if the port is in our blacklist: |
|
774 int32_t badPortListCnt = mRestrictedPortList.Length(); |
|
775 for (int i=0; i<badPortListCnt; i++) |
|
776 { |
|
777 if (port == mRestrictedPortList[i]) |
|
778 { |
|
779 *_retval = false; |
|
780 |
|
781 // check to see if the protocol wants to override |
|
782 if (!scheme) |
|
783 return NS_OK; |
|
784 |
|
785 nsCOMPtr<nsIProtocolHandler> handler; |
|
786 nsresult rv = GetProtocolHandler(scheme, getter_AddRefs(handler)); |
|
787 if (NS_FAILED(rv)) return rv; |
|
788 |
|
789 // let the protocol handler decide |
|
790 return handler->AllowPort(port, scheme, _retval); |
|
791 } |
|
792 } |
|
793 |
|
794 *_retval = true; |
|
795 return NS_OK; |
|
796 } |
|
797 |
|
798 //////////////////////////////////////////////////////////////////////////////// |
|
799 |
|
800 void |
|
801 nsIOService::PrefsChanged(nsIPrefBranch *prefs, const char *pref) |
|
802 { |
|
803 if (!prefs) return; |
|
804 |
|
805 // Look for extra ports to block |
|
806 if (!pref || strcmp(pref, PORT_PREF("banned")) == 0) |
|
807 ParsePortList(prefs, PORT_PREF("banned"), false); |
|
808 |
|
809 // ...as well as previous blocks to remove. |
|
810 if (!pref || strcmp(pref, PORT_PREF("banned.override")) == 0) |
|
811 ParsePortList(prefs, PORT_PREF("banned.override"), true); |
|
812 |
|
813 if (!pref || strcmp(pref, AUTODIAL_PREF) == 0) { |
|
814 bool enableAutodial = false; |
|
815 nsresult rv = prefs->GetBoolPref(AUTODIAL_PREF, &enableAutodial); |
|
816 // If pref not found, default to disabled. |
|
817 mAutoDialEnabled = enableAutodial; |
|
818 if (NS_SUCCEEDED(rv)) { |
|
819 if (mSocketTransportService) |
|
820 mSocketTransportService->SetAutodialEnabled(enableAutodial); |
|
821 } |
|
822 } |
|
823 |
|
824 if (!pref || strcmp(pref, MANAGE_OFFLINE_STATUS_PREF) == 0) { |
|
825 bool manage; |
|
826 if (mNetworkLinkServiceInitialized && |
|
827 NS_SUCCEEDED(prefs->GetBoolPref(MANAGE_OFFLINE_STATUS_PREF, |
|
828 &manage))) |
|
829 SetManageOfflineStatus(manage); |
|
830 } |
|
831 |
|
832 if (!pref || strcmp(pref, NECKO_BUFFER_CACHE_COUNT_PREF) == 0) { |
|
833 int32_t count; |
|
834 if (NS_SUCCEEDED(prefs->GetIntPref(NECKO_BUFFER_CACHE_COUNT_PREF, |
|
835 &count))) |
|
836 /* check for bogus values and default if we find such a value */ |
|
837 if (count > 0) |
|
838 gDefaultSegmentCount = count; |
|
839 } |
|
840 |
|
841 if (!pref || strcmp(pref, NECKO_BUFFER_CACHE_SIZE_PREF) == 0) { |
|
842 int32_t size; |
|
843 if (NS_SUCCEEDED(prefs->GetIntPref(NECKO_BUFFER_CACHE_SIZE_PREF, |
|
844 &size))) |
|
845 /* check for bogus values and default if we find such a value |
|
846 * the upper limit here is arbitrary. having a 1mb segment size |
|
847 * is pretty crazy. if you remove this, consider adding some |
|
848 * integer rollover test. |
|
849 */ |
|
850 if (size > 0 && size < 1024*1024) |
|
851 gDefaultSegmentSize = size; |
|
852 NS_WARN_IF_FALSE( (!(size & (size - 1))) , "network segment size is not a power of 2!"); |
|
853 } |
|
854 } |
|
855 |
|
856 void |
|
857 nsIOService::ParsePortList(nsIPrefBranch *prefBranch, const char *pref, bool remove) |
|
858 { |
|
859 nsXPIDLCString portList; |
|
860 |
|
861 // Get a pref string and chop it up into a list of ports. |
|
862 prefBranch->GetCharPref(pref, getter_Copies(portList)); |
|
863 if (portList) { |
|
864 nsTArray<nsCString> portListArray; |
|
865 ParseString(portList, ',', portListArray); |
|
866 uint32_t index; |
|
867 for (index=0; index < portListArray.Length(); index++) { |
|
868 portListArray[index].StripWhitespace(); |
|
869 int32_t portBegin, portEnd; |
|
870 |
|
871 if (PR_sscanf(portListArray[index].get(), "%d-%d", &portBegin, &portEnd) == 2) { |
|
872 if ((portBegin < 65536) && (portEnd < 65536)) { |
|
873 int32_t curPort; |
|
874 if (remove) { |
|
875 for (curPort=portBegin; curPort <= portEnd; curPort++) |
|
876 mRestrictedPortList.RemoveElement(curPort); |
|
877 } else { |
|
878 for (curPort=portBegin; curPort <= portEnd; curPort++) |
|
879 mRestrictedPortList.AppendElement(curPort); |
|
880 } |
|
881 } |
|
882 } else { |
|
883 nsresult aErrorCode; |
|
884 int32_t port = portListArray[index].ToInteger(&aErrorCode); |
|
885 if (NS_SUCCEEDED(aErrorCode) && port < 65536) { |
|
886 if (remove) |
|
887 mRestrictedPortList.RemoveElement(port); |
|
888 else |
|
889 mRestrictedPortList.AppendElement(port); |
|
890 } |
|
891 } |
|
892 |
|
893 } |
|
894 } |
|
895 } |
|
896 |
|
897 void |
|
898 nsIOService::GetPrefBranch(nsIPrefBranch **result) |
|
899 { |
|
900 *result = nullptr; |
|
901 CallGetService(NS_PREFSERVICE_CONTRACTID, result); |
|
902 } |
|
903 |
|
904 // nsIObserver interface |
|
905 NS_IMETHODIMP |
|
906 nsIOService::Observe(nsISupports *subject, |
|
907 const char *topic, |
|
908 const char16_t *data) |
|
909 { |
|
910 if (!strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) { |
|
911 nsCOMPtr<nsIPrefBranch> prefBranch = do_QueryInterface(subject); |
|
912 if (prefBranch) |
|
913 PrefsChanged(prefBranch, NS_ConvertUTF16toUTF8(data).get()); |
|
914 } |
|
915 else if (!strcmp(topic, kProfileChangeNetTeardownTopic)) { |
|
916 if (!mOffline) { |
|
917 mOfflineForProfileChange = true; |
|
918 SetOffline(true); |
|
919 } |
|
920 } |
|
921 else if (!strcmp(topic, kProfileChangeNetRestoreTopic)) { |
|
922 if (mOfflineForProfileChange) { |
|
923 mOfflineForProfileChange = false; |
|
924 if (!mManageOfflineStatus || |
|
925 NS_FAILED(TrackNetworkLinkStatusForOffline())) { |
|
926 SetOffline(false); |
|
927 } |
|
928 } |
|
929 } |
|
930 else if (!strcmp(topic, kProfileDoChange)) { |
|
931 if (data && NS_LITERAL_STRING("startup").Equals(data)) { |
|
932 // Lazy initialization of network link service (see bug 620472) |
|
933 InitializeNetworkLinkService(); |
|
934 // Set up the initilization flag regardless the actuall result. |
|
935 // If we fail here, we will fail always on. |
|
936 mNetworkLinkServiceInitialized = true; |
|
937 // And now reflect the preference setting |
|
938 nsCOMPtr<nsIPrefBranch> prefBranch; |
|
939 GetPrefBranch(getter_AddRefs(prefBranch)); |
|
940 PrefsChanged(prefBranch, MANAGE_OFFLINE_STATUS_PREF); |
|
941 } |
|
942 } |
|
943 else if (!strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) { |
|
944 // Remember we passed XPCOM shutdown notification to prevent any |
|
945 // changes of the offline status from now. We must not allow going |
|
946 // online after this point. |
|
947 mShutdown = true; |
|
948 |
|
949 SetOffline(true); |
|
950 |
|
951 // Break circular reference. |
|
952 mProxyService = nullptr; |
|
953 } |
|
954 else if (!strcmp(topic, NS_NETWORK_LINK_TOPIC)) { |
|
955 if (!mOfflineForProfileChange && mManageOfflineStatus) { |
|
956 TrackNetworkLinkStatusForOffline(); |
|
957 } |
|
958 } |
|
959 |
|
960 return NS_OK; |
|
961 } |
|
962 |
|
963 // nsINetUtil interface |
|
964 NS_IMETHODIMP |
|
965 nsIOService::ParseContentType(const nsACString &aTypeHeader, |
|
966 nsACString &aCharset, |
|
967 bool *aHadCharset, |
|
968 nsACString &aContentType) |
|
969 { |
|
970 net_ParseContentType(aTypeHeader, aContentType, aCharset, aHadCharset); |
|
971 return NS_OK; |
|
972 } |
|
973 |
|
974 NS_IMETHODIMP |
|
975 nsIOService::ProtocolHasFlags(nsIURI *uri, |
|
976 uint32_t flags, |
|
977 bool *result) |
|
978 { |
|
979 NS_ENSURE_ARG(uri); |
|
980 |
|
981 *result = false; |
|
982 nsAutoCString scheme; |
|
983 nsresult rv = uri->GetScheme(scheme); |
|
984 NS_ENSURE_SUCCESS(rv, rv); |
|
985 |
|
986 uint32_t protocolFlags; |
|
987 rv = GetProtocolFlags(scheme.get(), &protocolFlags); |
|
988 |
|
989 if (NS_SUCCEEDED(rv)) { |
|
990 *result = (protocolFlags & flags) == flags; |
|
991 } |
|
992 |
|
993 return rv; |
|
994 } |
|
995 |
|
996 NS_IMETHODIMP |
|
997 nsIOService::URIChainHasFlags(nsIURI *uri, |
|
998 uint32_t flags, |
|
999 bool *result) |
|
1000 { |
|
1001 nsresult rv = ProtocolHasFlags(uri, flags, result); |
|
1002 NS_ENSURE_SUCCESS(rv, rv); |
|
1003 |
|
1004 if (*result) { |
|
1005 return rv; |
|
1006 } |
|
1007 |
|
1008 // Dig deeper into the chain. Note that this is not a do/while loop to |
|
1009 // avoid the extra addref/release on |uri| in the common (non-nested) case. |
|
1010 nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(uri); |
|
1011 while (nestedURI) { |
|
1012 nsCOMPtr<nsIURI> innerURI; |
|
1013 rv = nestedURI->GetInnerURI(getter_AddRefs(innerURI)); |
|
1014 NS_ENSURE_SUCCESS(rv, rv); |
|
1015 |
|
1016 rv = ProtocolHasFlags(innerURI, flags, result); |
|
1017 |
|
1018 if (*result) { |
|
1019 return rv; |
|
1020 } |
|
1021 |
|
1022 nestedURI = do_QueryInterface(innerURI); |
|
1023 } |
|
1024 |
|
1025 return rv; |
|
1026 } |
|
1027 |
|
1028 NS_IMETHODIMP |
|
1029 nsIOService::ToImmutableURI(nsIURI* uri, nsIURI** result) |
|
1030 { |
|
1031 if (!uri) { |
|
1032 *result = nullptr; |
|
1033 return NS_OK; |
|
1034 } |
|
1035 |
|
1036 nsresult rv = NS_EnsureSafeToReturn(uri, result); |
|
1037 NS_ENSURE_SUCCESS(rv, rv); |
|
1038 |
|
1039 NS_TryToSetImmutable(*result); |
|
1040 return NS_OK; |
|
1041 } |
|
1042 |
|
1043 NS_IMETHODIMP |
|
1044 nsIOService::NewSimpleNestedURI(nsIURI* aURI, nsIURI** aResult) |
|
1045 { |
|
1046 NS_ENSURE_ARG(aURI); |
|
1047 |
|
1048 nsCOMPtr<nsIURI> safeURI; |
|
1049 nsresult rv = NS_EnsureSafeToReturn(aURI, getter_AddRefs(safeURI)); |
|
1050 NS_ENSURE_SUCCESS(rv, rv); |
|
1051 |
|
1052 NS_IF_ADDREF(*aResult = new nsSimpleNestedURI(safeURI)); |
|
1053 return *aResult ? NS_OK : NS_ERROR_OUT_OF_MEMORY; |
|
1054 } |
|
1055 |
|
1056 NS_IMETHODIMP |
|
1057 nsIOService::SetManageOfflineStatus(bool aManage) { |
|
1058 nsresult rv = NS_OK; |
|
1059 |
|
1060 // SetManageOfflineStatus must throw when we fail to go from non-managed |
|
1061 // to managed. Usually because there is no link monitoring service |
|
1062 // available. Failure to do this switch is detected by a failure of |
|
1063 // TrackNetworkLinkStatusForOffline(). When there is no network link |
|
1064 // available during call to InitializeNetworkLinkService(), application is |
|
1065 // put to offline mode. And when we change mMangeOfflineStatus to false |
|
1066 // on the next line we get stuck on being offline even though the link |
|
1067 // becomes later available. |
|
1068 bool wasManaged = mManageOfflineStatus; |
|
1069 mManageOfflineStatus = aManage; |
|
1070 |
|
1071 InitializeNetworkLinkService(); |
|
1072 |
|
1073 if (mManageOfflineStatus && !wasManaged) { |
|
1074 rv = TrackNetworkLinkStatusForOffline(); |
|
1075 if (NS_FAILED(rv)) |
|
1076 mManageOfflineStatus = false; |
|
1077 } |
|
1078 return rv; |
|
1079 } |
|
1080 |
|
1081 NS_IMETHODIMP |
|
1082 nsIOService::GetManageOfflineStatus(bool* aManage) { |
|
1083 *aManage = mManageOfflineStatus; |
|
1084 return NS_OK; |
|
1085 } |
|
1086 |
|
1087 nsresult |
|
1088 nsIOService::TrackNetworkLinkStatusForOffline() |
|
1089 { |
|
1090 NS_ASSERTION(mManageOfflineStatus, |
|
1091 "Don't call this unless we're managing the offline status"); |
|
1092 if (!mNetworkLinkService) |
|
1093 return NS_ERROR_FAILURE; |
|
1094 |
|
1095 if (mShutdown) |
|
1096 return NS_ERROR_NOT_AVAILABLE; |
|
1097 |
|
1098 // check to make sure this won't collide with Autodial |
|
1099 if (mSocketTransportService) { |
|
1100 bool autodialEnabled = false; |
|
1101 mSocketTransportService->GetAutodialEnabled(&autodialEnabled); |
|
1102 // If autodialing-on-link-down is enabled, check if the OS auto dial |
|
1103 // option is set to always autodial. If so, then we are |
|
1104 // always up for the purposes of offline management. |
|
1105 if (autodialEnabled) { |
|
1106 #if defined(XP_WIN) |
|
1107 // On Windows, we should first check with the OS |
|
1108 // to see if autodial is enabled. If it is |
|
1109 // enabled then we are allowed to manage the |
|
1110 // offline state. |
|
1111 if(nsNativeConnectionHelper::IsAutodialEnabled()) |
|
1112 return SetOffline(false); |
|
1113 #else |
|
1114 return SetOffline(false); |
|
1115 #endif |
|
1116 } |
|
1117 } |
|
1118 |
|
1119 bool isUp; |
|
1120 nsresult rv = mNetworkLinkService->GetIsLinkUp(&isUp); |
|
1121 NS_ENSURE_SUCCESS(rv, rv); |
|
1122 return SetOffline(!isUp); |
|
1123 } |
|
1124 |
|
1125 NS_IMETHODIMP |
|
1126 nsIOService::EscapeString(const nsACString& aString, |
|
1127 uint32_t aEscapeType, |
|
1128 nsACString& aResult) |
|
1129 { |
|
1130 NS_ENSURE_ARG_MAX(aEscapeType, 4); |
|
1131 |
|
1132 nsAutoCString stringCopy(aString); |
|
1133 nsCString result; |
|
1134 |
|
1135 if (!NS_Escape(stringCopy, result, (nsEscapeMask) aEscapeType)) |
|
1136 return NS_ERROR_OUT_OF_MEMORY; |
|
1137 |
|
1138 aResult.Assign(result); |
|
1139 |
|
1140 return NS_OK; |
|
1141 } |
|
1142 |
|
1143 NS_IMETHODIMP |
|
1144 nsIOService::EscapeURL(const nsACString &aStr, |
|
1145 uint32_t aFlags, nsACString &aResult) |
|
1146 { |
|
1147 aResult.Truncate(); |
|
1148 NS_EscapeURL(aStr.BeginReading(), aStr.Length(), |
|
1149 aFlags | esc_AlwaysCopy, aResult); |
|
1150 return NS_OK; |
|
1151 } |
|
1152 |
|
1153 NS_IMETHODIMP |
|
1154 nsIOService::UnescapeString(const nsACString &aStr, |
|
1155 uint32_t aFlags, nsACString &aResult) |
|
1156 { |
|
1157 aResult.Truncate(); |
|
1158 NS_UnescapeURL(aStr.BeginReading(), aStr.Length(), |
|
1159 aFlags | esc_AlwaysCopy, aResult); |
|
1160 return NS_OK; |
|
1161 } |
|
1162 |
|
1163 NS_IMETHODIMP |
|
1164 nsIOService::ExtractCharsetFromContentType(const nsACString &aTypeHeader, |
|
1165 nsACString &aCharset, |
|
1166 int32_t *aCharsetStart, |
|
1167 int32_t *aCharsetEnd, |
|
1168 bool *aHadCharset) |
|
1169 { |
|
1170 nsAutoCString ignored; |
|
1171 net_ParseContentType(aTypeHeader, ignored, aCharset, aHadCharset, |
|
1172 aCharsetStart, aCharsetEnd); |
|
1173 if (*aHadCharset && *aCharsetStart == *aCharsetEnd) { |
|
1174 *aHadCharset = false; |
|
1175 } |
|
1176 return NS_OK; |
|
1177 } |
|
1178 |
|
1179 // nsISpeculativeConnect |
|
1180 class IOServiceProxyCallback MOZ_FINAL : public nsIProtocolProxyCallback |
|
1181 { |
|
1182 public: |
|
1183 NS_DECL_ISUPPORTS |
|
1184 NS_DECL_NSIPROTOCOLPROXYCALLBACK |
|
1185 |
|
1186 IOServiceProxyCallback(nsIInterfaceRequestor *aCallbacks, |
|
1187 nsIOService *aIOService) |
|
1188 : mCallbacks(aCallbacks) |
|
1189 , mIOService(aIOService) |
|
1190 { } |
|
1191 |
|
1192 private: |
|
1193 nsRefPtr<nsIInterfaceRequestor> mCallbacks; |
|
1194 nsRefPtr<nsIOService> mIOService; |
|
1195 }; |
|
1196 |
|
1197 NS_IMPL_ISUPPORTS(IOServiceProxyCallback, nsIProtocolProxyCallback) |
|
1198 |
|
1199 NS_IMETHODIMP |
|
1200 IOServiceProxyCallback::OnProxyAvailable(nsICancelable *request, nsIChannel *channel, |
|
1201 nsIProxyInfo *pi, nsresult status) |
|
1202 { |
|
1203 // Checking proxy status for speculative connect |
|
1204 nsAutoCString type; |
|
1205 if (NS_SUCCEEDED(status) && pi && |
|
1206 NS_SUCCEEDED(pi->GetType(type)) && |
|
1207 !type.EqualsLiteral("direct")) { |
|
1208 // proxies dont do speculative connect |
|
1209 return NS_OK; |
|
1210 } |
|
1211 |
|
1212 nsCOMPtr<nsIURI> uri; |
|
1213 nsresult rv = channel->GetURI(getter_AddRefs(uri)); |
|
1214 if (NS_FAILED(rv)) |
|
1215 return NS_OK; |
|
1216 |
|
1217 nsAutoCString scheme; |
|
1218 rv = uri->GetScheme(scheme); |
|
1219 if (NS_FAILED(rv)) |
|
1220 return NS_OK; |
|
1221 |
|
1222 nsCOMPtr<nsIProtocolHandler> handler; |
|
1223 rv = mIOService->GetProtocolHandler(scheme.get(), |
|
1224 getter_AddRefs(handler)); |
|
1225 if (NS_FAILED(rv)) |
|
1226 return NS_OK; |
|
1227 |
|
1228 nsCOMPtr<nsISpeculativeConnect> speculativeHandler = |
|
1229 do_QueryInterface(handler); |
|
1230 if (!speculativeHandler) |
|
1231 return NS_OK; |
|
1232 |
|
1233 speculativeHandler->SpeculativeConnect(uri, |
|
1234 mCallbacks); |
|
1235 return NS_OK; |
|
1236 } |
|
1237 |
|
1238 NS_IMETHODIMP |
|
1239 nsIOService::SpeculativeConnect(nsIURI *aURI, |
|
1240 nsIInterfaceRequestor *aCallbacks) |
|
1241 { |
|
1242 // Check for proxy information. If there is a proxy configured then a |
|
1243 // speculative connect should not be performed because the potential |
|
1244 // reward is slim with tcp peers closely located to the browser. |
|
1245 nsresult rv; |
|
1246 nsCOMPtr<nsIProtocolProxyService> pps = |
|
1247 do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv); |
|
1248 if (NS_FAILED(rv)) |
|
1249 return rv; |
|
1250 |
|
1251 nsCOMPtr<nsIChannel> channel; |
|
1252 rv = NewChannelFromURI(aURI, getter_AddRefs(channel)); |
|
1253 if (NS_FAILED(rv)) |
|
1254 return rv; |
|
1255 |
|
1256 nsCOMPtr<nsICancelable> cancelable; |
|
1257 nsRefPtr<IOServiceProxyCallback> callback = |
|
1258 new IOServiceProxyCallback(aCallbacks, this); |
|
1259 return pps->AsyncResolve(channel, 0, callback, getter_AddRefs(cancelable)); |
|
1260 } |