1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/netwerk/base/src/nsIOService.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1260 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* vim:set ts=4 sw=4 cindent et: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "mozilla/DebugOnly.h" 1.11 + 1.12 +#include "nsIOService.h" 1.13 +#include "nsIProtocolHandler.h" 1.14 +#include "nsIFileProtocolHandler.h" 1.15 +#include "nscore.h" 1.16 +#include "nsIURI.h" 1.17 +#include "prprf.h" 1.18 +#include "nsIErrorService.h" 1.19 +#include "netCore.h" 1.20 +#include "nsIObserverService.h" 1.21 +#include "nsIPrefService.h" 1.22 +#include "nsXPCOM.h" 1.23 +#include "nsIProxiedProtocolHandler.h" 1.24 +#include "nsIProxyInfo.h" 1.25 +#include "nsEscape.h" 1.26 +#include "nsNetCID.h" 1.27 +#include "nsCRT.h" 1.28 +#include "nsSimpleNestedURI.h" 1.29 +#include "nsNetUtil.h" 1.30 +#include "nsTArray.h" 1.31 +#include "nsIConsoleService.h" 1.32 +#include "nsIUploadChannel2.h" 1.33 +#include "nsXULAppAPI.h" 1.34 +#include "nsIProtocolProxyCallback.h" 1.35 +#include "nsICancelable.h" 1.36 +#include "nsINetworkLinkService.h" 1.37 +#include "nsPISocketTransportService.h" 1.38 +#include "nsAsyncRedirectVerifyHelper.h" 1.39 +#include "nsURLHelper.h" 1.40 +#include "nsPIDNSService.h" 1.41 +#include "nsIProtocolProxyService2.h" 1.42 +#include "MainThreadUtils.h" 1.43 + 1.44 +#if defined(XP_WIN) 1.45 +#include "nsNativeConnectionHelper.h" 1.46 +#endif 1.47 + 1.48 +using namespace mozilla; 1.49 + 1.50 +#define PORT_PREF_PREFIX "network.security.ports." 1.51 +#define PORT_PREF(x) PORT_PREF_PREFIX x 1.52 +#define AUTODIAL_PREF "network.autodial-helper.enabled" 1.53 +#define MANAGE_OFFLINE_STATUS_PREF "network.manage-offline-status" 1.54 + 1.55 +// Nb: these have been misnomers since bug 715770 removed the buffer cache. 1.56 +// "network.segment.count" and "network.segment.size" would be better names, 1.57 +// but the old names are still used to preserve backward compatibility. 1.58 +#define NECKO_BUFFER_CACHE_COUNT_PREF "network.buffer.cache.count" 1.59 +#define NECKO_BUFFER_CACHE_SIZE_PREF "network.buffer.cache.size" 1.60 + 1.61 +#define MAX_RECURSION_COUNT 50 1.62 + 1.63 +nsIOService* gIOService = nullptr; 1.64 +static bool gHasWarnedUploadChannel2; 1.65 + 1.66 +// A general port blacklist. Connections to these ports will not be allowed unless 1.67 +// the protocol overrides. 1.68 +// 1.69 +// TODO: I am sure that there are more ports to be added. 1.70 +// This cut is based on the classic mozilla codebase 1.71 + 1.72 +int16_t gBadPortList[] = { 1.73 + 1, // tcpmux 1.74 + 7, // echo 1.75 + 9, // discard 1.76 + 11, // systat 1.77 + 13, // daytime 1.78 + 15, // netstat 1.79 + 17, // qotd 1.80 + 19, // chargen 1.81 + 20, // ftp-data 1.82 + 21, // ftp-cntl 1.83 + 22, // ssh 1.84 + 23, // telnet 1.85 + 25, // smtp 1.86 + 37, // time 1.87 + 42, // name 1.88 + 43, // nicname 1.89 + 53, // domain 1.90 + 77, // priv-rjs 1.91 + 79, // finger 1.92 + 87, // ttylink 1.93 + 95, // supdup 1.94 + 101, // hostriame 1.95 + 102, // iso-tsap 1.96 + 103, // gppitnp 1.97 + 104, // acr-nema 1.98 + 109, // pop2 1.99 + 110, // pop3 1.100 + 111, // sunrpc 1.101 + 113, // auth 1.102 + 115, // sftp 1.103 + 117, // uucp-path 1.104 + 119, // nntp 1.105 + 123, // NTP 1.106 + 135, // loc-srv / epmap 1.107 + 139, // netbios 1.108 + 143, // imap2 1.109 + 179, // BGP 1.110 + 389, // ldap 1.111 + 465, // smtp+ssl 1.112 + 512, // print / exec 1.113 + 513, // login 1.114 + 514, // shell 1.115 + 515, // printer 1.116 + 526, // tempo 1.117 + 530, // courier 1.118 + 531, // Chat 1.119 + 532, // netnews 1.120 + 540, // uucp 1.121 + 556, // remotefs 1.122 + 563, // nntp+ssl 1.123 + 587, // 1.124 + 601, // 1.125 + 636, // ldap+ssl 1.126 + 993, // imap+ssl 1.127 + 995, // pop3+ssl 1.128 + 2049, // nfs 1.129 + 4045, // lockd 1.130 + 6000, // x11 1.131 + 0, // This MUST be zero so that we can populating the array 1.132 +}; 1.133 + 1.134 +static const char kProfileChangeNetTeardownTopic[] = "profile-change-net-teardown"; 1.135 +static const char kProfileChangeNetRestoreTopic[] = "profile-change-net-restore"; 1.136 +static const char kProfileDoChange[] = "profile-do-change"; 1.137 + 1.138 +// Necko buffer defaults 1.139 +uint32_t nsIOService::gDefaultSegmentSize = 4096; 1.140 +uint32_t nsIOService::gDefaultSegmentCount = 24; 1.141 + 1.142 +//////////////////////////////////////////////////////////////////////////////// 1.143 + 1.144 +nsIOService::nsIOService() 1.145 + : mOffline(true) 1.146 + , mOfflineForProfileChange(false) 1.147 + , mManageOfflineStatus(false) 1.148 + , mSettingOffline(false) 1.149 + , mSetOfflineValue(false) 1.150 + , mShutdown(false) 1.151 + , mNetworkLinkServiceInitialized(false) 1.152 + , mChannelEventSinks(NS_CHANNEL_EVENT_SINK_CATEGORY) 1.153 + , mAutoDialEnabled(false) 1.154 +{ 1.155 +} 1.156 + 1.157 +nsresult 1.158 +nsIOService::Init() 1.159 +{ 1.160 + nsresult rv; 1.161 + 1.162 + // We need to get references to the DNS service so that we can shut it 1.163 + // down later. If we wait until the nsIOService is being shut down, 1.164 + // GetService will fail at that point. 1.165 + 1.166 + mDNSService = do_GetService(NS_DNSSERVICE_CONTRACTID, &rv); 1.167 + if (NS_FAILED(rv)) { 1.168 + NS_WARNING("failed to get DNS service"); 1.169 + return rv; 1.170 + } 1.171 + 1.172 + // XXX hack until xpidl supports error info directly (bug 13423) 1.173 + nsCOMPtr<nsIErrorService> errorService = do_GetService(NS_ERRORSERVICE_CONTRACTID); 1.174 + if (errorService) { 1.175 + errorService->RegisterErrorStringBundle(NS_ERROR_MODULE_NETWORK, NECKO_MSGS_URL); 1.176 + } 1.177 + else 1.178 + NS_WARNING("failed to get error service"); 1.179 + 1.180 + // setup our bad port list stuff 1.181 + for(int i=0; gBadPortList[i]; i++) 1.182 + mRestrictedPortList.AppendElement(gBadPortList[i]); 1.183 + 1.184 + // Further modifications to the port list come from prefs 1.185 + nsCOMPtr<nsIPrefBranch> prefBranch; 1.186 + GetPrefBranch(getter_AddRefs(prefBranch)); 1.187 + if (prefBranch) { 1.188 + prefBranch->AddObserver(PORT_PREF_PREFIX, this, true); 1.189 + prefBranch->AddObserver(AUTODIAL_PREF, this, true); 1.190 + prefBranch->AddObserver(MANAGE_OFFLINE_STATUS_PREF, this, true); 1.191 + prefBranch->AddObserver(NECKO_BUFFER_CACHE_COUNT_PREF, this, true); 1.192 + prefBranch->AddObserver(NECKO_BUFFER_CACHE_SIZE_PREF, this, true); 1.193 + PrefsChanged(prefBranch); 1.194 + } 1.195 + 1.196 + // Register for profile change notifications 1.197 + nsCOMPtr<nsIObserverService> observerService = 1.198 + mozilla::services::GetObserverService(); 1.199 + if (observerService) { 1.200 + observerService->AddObserver(this, kProfileChangeNetTeardownTopic, true); 1.201 + observerService->AddObserver(this, kProfileChangeNetRestoreTopic, true); 1.202 + observerService->AddObserver(this, kProfileDoChange, true); 1.203 + observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, true); 1.204 + observerService->AddObserver(this, NS_NETWORK_LINK_TOPIC, true); 1.205 + } 1.206 + else 1.207 + NS_WARNING("failed to get observer service"); 1.208 + 1.209 + gIOService = this; 1.210 + 1.211 + InitializeNetworkLinkService(); 1.212 + 1.213 + return NS_OK; 1.214 +} 1.215 + 1.216 + 1.217 +nsIOService::~nsIOService() 1.218 +{ 1.219 + gIOService = nullptr; 1.220 +} 1.221 + 1.222 +nsresult 1.223 +nsIOService::InitializeSocketTransportService() 1.224 +{ 1.225 + nsresult rv = NS_OK; 1.226 + 1.227 + if (!mSocketTransportService) { 1.228 + mSocketTransportService = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); 1.229 + if (NS_FAILED(rv)) { 1.230 + NS_WARNING("failed to get socket transport service"); 1.231 + } 1.232 + } 1.233 + 1.234 + if (mSocketTransportService) { 1.235 + rv = mSocketTransportService->Init(); 1.236 + NS_ASSERTION(NS_SUCCEEDED(rv), "socket transport service init failed"); 1.237 + mSocketTransportService->SetAutodialEnabled(mAutoDialEnabled); 1.238 + mSocketTransportService->SetOffline(false); 1.239 + } 1.240 + 1.241 + return rv; 1.242 +} 1.243 + 1.244 +nsresult 1.245 +nsIOService::InitializeNetworkLinkService() 1.246 +{ 1.247 + nsresult rv = NS_OK; 1.248 + 1.249 + if (mNetworkLinkServiceInitialized) 1.250 + return rv; 1.251 + 1.252 + if (!NS_IsMainThread()) { 1.253 + NS_WARNING("Network link service should be created on main thread"); 1.254 + return NS_ERROR_FAILURE; 1.255 + } 1.256 + 1.257 + // go into managed mode if we can, and chrome process 1.258 + if (XRE_GetProcessType() == GeckoProcessType_Default) 1.259 + { 1.260 + mNetworkLinkService = do_GetService(NS_NETWORK_LINK_SERVICE_CONTRACTID, &rv); 1.261 + } 1.262 + 1.263 + if (mNetworkLinkService) { 1.264 + mNetworkLinkServiceInitialized = true; 1.265 + } 1.266 + else { 1.267 + // We can't really determine if the machine has a usable network connection, 1.268 + // so let's cross our fingers! 1.269 + mManageOfflineStatus = false; 1.270 + } 1.271 + 1.272 + 1.273 + if (mManageOfflineStatus) 1.274 + TrackNetworkLinkStatusForOffline(); 1.275 + else 1.276 + SetOffline(false); 1.277 + 1.278 + return rv; 1.279 +} 1.280 + 1.281 +nsIOService* 1.282 +nsIOService::GetInstance() { 1.283 + if (!gIOService) { 1.284 + gIOService = new nsIOService(); 1.285 + if (!gIOService) 1.286 + return nullptr; 1.287 + NS_ADDREF(gIOService); 1.288 + 1.289 + nsresult rv = gIOService->Init(); 1.290 + if (NS_FAILED(rv)) { 1.291 + NS_RELEASE(gIOService); 1.292 + return nullptr; 1.293 + } 1.294 + return gIOService; 1.295 + } 1.296 + NS_ADDREF(gIOService); 1.297 + return gIOService; 1.298 +} 1.299 + 1.300 +NS_IMPL_ISUPPORTS(nsIOService, 1.301 + nsIIOService, 1.302 + nsIIOService2, 1.303 + nsINetUtil, 1.304 + nsISpeculativeConnect, 1.305 + nsIObserver, 1.306 + nsISupportsWeakReference) 1.307 + 1.308 +//////////////////////////////////////////////////////////////////////////////// 1.309 + 1.310 +nsresult 1.311 +nsIOService::AsyncOnChannelRedirect(nsIChannel* oldChan, nsIChannel* newChan, 1.312 + uint32_t flags, 1.313 + nsAsyncRedirectVerifyHelper *helper) 1.314 +{ 1.315 + nsCOMPtr<nsIChannelEventSink> sink = 1.316 + do_GetService(NS_GLOBAL_CHANNELEVENTSINK_CONTRACTID); 1.317 + if (sink) { 1.318 + nsresult rv = helper->DelegateOnChannelRedirect(sink, oldChan, 1.319 + newChan, flags); 1.320 + if (NS_FAILED(rv)) 1.321 + return rv; 1.322 + } 1.323 + 1.324 + // Finally, our category 1.325 + nsCOMArray<nsIChannelEventSink> entries; 1.326 + mChannelEventSinks.GetEntries(entries); 1.327 + int32_t len = entries.Count(); 1.328 + for (int32_t i = 0; i < len; ++i) { 1.329 + nsresult rv = helper->DelegateOnChannelRedirect(entries[i], oldChan, 1.330 + newChan, flags); 1.331 + if (NS_FAILED(rv)) 1.332 + return rv; 1.333 + } 1.334 + return NS_OK; 1.335 +} 1.336 + 1.337 +nsresult 1.338 +nsIOService::CacheProtocolHandler(const char *scheme, nsIProtocolHandler *handler) 1.339 +{ 1.340 + for (unsigned int i=0; i<NS_N(gScheme); i++) 1.341 + { 1.342 + if (!nsCRT::strcasecmp(scheme, gScheme[i])) 1.343 + { 1.344 + nsresult rv; 1.345 + NS_ASSERTION(!mWeakHandler[i], "Protocol handler already cached"); 1.346 + // Make sure the handler supports weak references. 1.347 + nsCOMPtr<nsISupportsWeakReference> factoryPtr = do_QueryInterface(handler, &rv); 1.348 + if (!factoryPtr) 1.349 + { 1.350 + // Don't cache handlers that don't support weak reference as 1.351 + // there is real danger of a circular reference. 1.352 +#ifdef DEBUG_dp 1.353 + printf("DEBUG: %s protcol handler doesn't support weak ref. Not cached.\n", scheme); 1.354 +#endif /* DEBUG_dp */ 1.355 + return NS_ERROR_FAILURE; 1.356 + } 1.357 + mWeakHandler[i] = do_GetWeakReference(handler); 1.358 + return NS_OK; 1.359 + } 1.360 + } 1.361 + return NS_ERROR_FAILURE; 1.362 +} 1.363 + 1.364 +nsresult 1.365 +nsIOService::GetCachedProtocolHandler(const char *scheme, nsIProtocolHandler **result, uint32_t start, uint32_t end) 1.366 +{ 1.367 + uint32_t len = end - start - 1; 1.368 + for (unsigned int i=0; i<NS_N(gScheme); i++) 1.369 + { 1.370 + if (!mWeakHandler[i]) 1.371 + continue; 1.372 + 1.373 + // handle unterminated strings 1.374 + // start is inclusive, end is exclusive, len = end - start - 1 1.375 + if (end ? (!nsCRT::strncasecmp(scheme + start, gScheme[i], len) 1.376 + && gScheme[i][len] == '\0') 1.377 + : (!nsCRT::strcasecmp(scheme, gScheme[i]))) 1.378 + { 1.379 + return CallQueryReferent(mWeakHandler[i].get(), result); 1.380 + } 1.381 + } 1.382 + return NS_ERROR_FAILURE; 1.383 +} 1.384 + 1.385 +NS_IMETHODIMP 1.386 +nsIOService::GetProtocolHandler(const char* scheme, nsIProtocolHandler* *result) 1.387 +{ 1.388 + nsresult rv; 1.389 + 1.390 + NS_ENSURE_ARG_POINTER(scheme); 1.391 + // XXX we may want to speed this up by introducing our own protocol 1.392 + // scheme -> protocol handler mapping, avoiding the string manipulation 1.393 + // and service manager stuff 1.394 + 1.395 + rv = GetCachedProtocolHandler(scheme, result); 1.396 + if (NS_SUCCEEDED(rv)) 1.397 + return rv; 1.398 + 1.399 + bool externalProtocol = false; 1.400 + nsCOMPtr<nsIPrefBranch> prefBranch; 1.401 + GetPrefBranch(getter_AddRefs(prefBranch)); 1.402 + if (prefBranch) { 1.403 + nsAutoCString externalProtocolPref("network.protocol-handler.external."); 1.404 + externalProtocolPref += scheme; 1.405 + rv = prefBranch->GetBoolPref(externalProtocolPref.get(), &externalProtocol); 1.406 + if (NS_FAILED(rv)) { 1.407 + externalProtocol = false; 1.408 + } 1.409 + } 1.410 + 1.411 + if (!externalProtocol) { 1.412 + nsAutoCString contractID(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX); 1.413 + contractID += scheme; 1.414 + ToLowerCase(contractID); 1.415 + 1.416 + rv = CallGetService(contractID.get(), result); 1.417 + if (NS_SUCCEEDED(rv)) { 1.418 + CacheProtocolHandler(scheme, *result); 1.419 + return rv; 1.420 + } 1.421 + 1.422 +#ifdef MOZ_X11 1.423 + // check to see whether GVFS can handle this URI scheme. if it can 1.424 + // create a nsIURI for the "scheme:", then we assume it has support for 1.425 + // the requested protocol. otherwise, we failover to using the default 1.426 + // protocol handler. 1.427 + 1.428 + rv = CallGetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX"moz-gio", 1.429 + result); 1.430 + if (NS_SUCCEEDED(rv)) { 1.431 + nsAutoCString spec(scheme); 1.432 + spec.Append(':'); 1.433 + 1.434 + nsIURI *uri; 1.435 + rv = (*result)->NewURI(spec, nullptr, nullptr, &uri); 1.436 + if (NS_SUCCEEDED(rv)) { 1.437 + NS_RELEASE(uri); 1.438 + return rv; 1.439 + } 1.440 + 1.441 + NS_RELEASE(*result); 1.442 + } 1.443 + 1.444 + // check to see whether GnomeVFS can handle this URI scheme. if it can 1.445 + // create a nsIURI for the "scheme:", then we assume it has support for 1.446 + // the requested protocol. otherwise, we failover to using the default 1.447 + // protocol handler. 1.448 + 1.449 + // XXX should this be generalized into something that searches a 1.450 + // category? (see bug 234714) 1.451 + 1.452 + rv = CallGetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX"moz-gnomevfs", 1.453 + result); 1.454 + if (NS_SUCCEEDED(rv)) { 1.455 + nsAutoCString spec(scheme); 1.456 + spec.Append(':'); 1.457 + 1.458 + nsIURI *uri; 1.459 + rv = (*result)->NewURI(spec, nullptr, nullptr, &uri); 1.460 + if (NS_SUCCEEDED(rv)) { 1.461 + NS_RELEASE(uri); 1.462 + return rv; 1.463 + } 1.464 + 1.465 + NS_RELEASE(*result); 1.466 + } 1.467 +#endif 1.468 + } 1.469 + 1.470 + // Okay we don't have a protocol handler to handle this url type, so use 1.471 + // the default protocol handler. This will cause urls to get dispatched 1.472 + // out to the OS ('cause we can't do anything with them) when we try to 1.473 + // read from a channel created by the default protocol handler. 1.474 + 1.475 + rv = CallGetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX"default", 1.476 + result); 1.477 + if (NS_FAILED(rv)) 1.478 + return NS_ERROR_UNKNOWN_PROTOCOL; 1.479 + 1.480 + return rv; 1.481 +} 1.482 + 1.483 +NS_IMETHODIMP 1.484 +nsIOService::ExtractScheme(const nsACString &inURI, nsACString &scheme) 1.485 +{ 1.486 + return net_ExtractURLScheme(inURI, nullptr, nullptr, &scheme); 1.487 +} 1.488 + 1.489 +NS_IMETHODIMP 1.490 +nsIOService::GetProtocolFlags(const char* scheme, uint32_t *flags) 1.491 +{ 1.492 + nsCOMPtr<nsIProtocolHandler> handler; 1.493 + nsresult rv = GetProtocolHandler(scheme, getter_AddRefs(handler)); 1.494 + if (NS_FAILED(rv)) return rv; 1.495 + 1.496 + rv = handler->GetProtocolFlags(flags); 1.497 + return rv; 1.498 +} 1.499 + 1.500 +class AutoIncrement 1.501 +{ 1.502 + public: 1.503 + AutoIncrement(uint32_t *var) : mVar(var) 1.504 + { 1.505 + ++*var; 1.506 + } 1.507 + ~AutoIncrement() 1.508 + { 1.509 + --*mVar; 1.510 + } 1.511 + private: 1.512 + uint32_t *mVar; 1.513 +}; 1.514 + 1.515 +nsresult 1.516 +nsIOService::NewURI(const nsACString &aSpec, const char *aCharset, nsIURI *aBaseURI, nsIURI **result) 1.517 +{ 1.518 + NS_ASSERTION(NS_IsMainThread(), "wrong thread"); 1.519 + 1.520 + static uint32_t recursionCount = 0; 1.521 + if (recursionCount >= MAX_RECURSION_COUNT) 1.522 + return NS_ERROR_MALFORMED_URI; 1.523 + AutoIncrement inc(&recursionCount); 1.524 + 1.525 + nsAutoCString scheme; 1.526 + nsresult rv = ExtractScheme(aSpec, scheme); 1.527 + if (NS_FAILED(rv)) { 1.528 + // then aSpec is relative 1.529 + if (!aBaseURI) 1.530 + return NS_ERROR_MALFORMED_URI; 1.531 + 1.532 + rv = aBaseURI->GetScheme(scheme); 1.533 + if (NS_FAILED(rv)) return rv; 1.534 + } 1.535 + 1.536 + // now get the handler for this scheme 1.537 + nsCOMPtr<nsIProtocolHandler> handler; 1.538 + rv = GetProtocolHandler(scheme.get(), getter_AddRefs(handler)); 1.539 + if (NS_FAILED(rv)) return rv; 1.540 + 1.541 + return handler->NewURI(aSpec, aCharset, aBaseURI, result); 1.542 +} 1.543 + 1.544 + 1.545 +NS_IMETHODIMP 1.546 +nsIOService::NewFileURI(nsIFile *file, nsIURI **result) 1.547 +{ 1.548 + nsresult rv; 1.549 + NS_ENSURE_ARG_POINTER(file); 1.550 + 1.551 + nsCOMPtr<nsIProtocolHandler> handler; 1.552 + 1.553 + rv = GetProtocolHandler("file", getter_AddRefs(handler)); 1.554 + if (NS_FAILED(rv)) return rv; 1.555 + 1.556 + nsCOMPtr<nsIFileProtocolHandler> fileHandler( do_QueryInterface(handler, &rv) ); 1.557 + if (NS_FAILED(rv)) return rv; 1.558 + 1.559 + return fileHandler->NewFileURI(file, result); 1.560 +} 1.561 + 1.562 +NS_IMETHODIMP 1.563 +nsIOService::NewChannelFromURI(nsIURI *aURI, nsIChannel **result) 1.564 +{ 1.565 + return NewChannelFromURIWithProxyFlags(aURI, nullptr, 0, result); 1.566 +} 1.567 + 1.568 +NS_IMETHODIMP 1.569 +nsIOService::NewChannelFromURIWithProxyFlags(nsIURI *aURI, 1.570 + nsIURI *aProxyURI, 1.571 + uint32_t aProxyFlags, 1.572 + nsIChannel **result) 1.573 +{ 1.574 + nsresult rv; 1.575 + NS_ENSURE_ARG_POINTER(aURI); 1.576 + 1.577 + nsAutoCString scheme; 1.578 + rv = aURI->GetScheme(scheme); 1.579 + if (NS_FAILED(rv)) 1.580 + return rv; 1.581 + 1.582 + nsCOMPtr<nsIProtocolHandler> handler; 1.583 + rv = GetProtocolHandler(scheme.get(), getter_AddRefs(handler)); 1.584 + if (NS_FAILED(rv)) 1.585 + return rv; 1.586 + 1.587 + uint32_t protoFlags; 1.588 + rv = handler->GetProtocolFlags(&protoFlags); 1.589 + if (NS_FAILED(rv)) 1.590 + return rv; 1.591 + 1.592 + nsCOMPtr<nsIProxiedProtocolHandler> pph = do_QueryInterface(handler); 1.593 + if (pph) 1.594 + rv = pph->NewProxiedChannel(aURI, nullptr, aProxyFlags, aProxyURI, result); 1.595 + else 1.596 + rv = handler->NewChannel(aURI, result); 1.597 + NS_ENSURE_SUCCESS(rv, rv); 1.598 + 1.599 + // Some extensions override the http protocol handler and provide their own 1.600 + // implementation. The channels returned from that implementation doesn't 1.601 + // seem to always implement the nsIUploadChannel2 interface, presumably 1.602 + // because it's a new interface. 1.603 + // Eventually we should remove this and simply require that http channels 1.604 + // implement the new interface. 1.605 + // See bug 529041 1.606 + if (!gHasWarnedUploadChannel2 && scheme.EqualsLiteral("http")) { 1.607 + nsCOMPtr<nsIUploadChannel2> uploadChannel2 = do_QueryInterface(*result); 1.608 + if (!uploadChannel2) { 1.609 + nsCOMPtr<nsIConsoleService> consoleService = 1.610 + do_GetService(NS_CONSOLESERVICE_CONTRACTID); 1.611 + if (consoleService) { 1.612 + consoleService->LogStringMessage(NS_LITERAL_STRING( 1.613 + "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." 1.614 + ).get()); 1.615 + } 1.616 + gHasWarnedUploadChannel2 = true; 1.617 + } 1.618 + } 1.619 + 1.620 + return NS_OK; 1.621 +} 1.622 + 1.623 +NS_IMETHODIMP 1.624 +nsIOService::NewChannel(const nsACString &aSpec, const char *aCharset, nsIURI *aBaseURI, nsIChannel **result) 1.625 +{ 1.626 + nsresult rv; 1.627 + nsCOMPtr<nsIURI> uri; 1.628 + rv = NewURI(aSpec, aCharset, aBaseURI, getter_AddRefs(uri)); 1.629 + if (NS_FAILED(rv)) return rv; 1.630 + 1.631 + return NewChannelFromURI(uri, result); 1.632 +} 1.633 + 1.634 +bool 1.635 +nsIOService::IsLinkUp() 1.636 +{ 1.637 + InitializeNetworkLinkService(); 1.638 + 1.639 + if (!mNetworkLinkService) { 1.640 + // We cannot decide, assume the link is up 1.641 + return true; 1.642 + } 1.643 + 1.644 + bool isLinkUp; 1.645 + nsresult rv; 1.646 + rv = mNetworkLinkService->GetIsLinkUp(&isLinkUp); 1.647 + if (NS_FAILED(rv)) { 1.648 + return true; 1.649 + } 1.650 + 1.651 + return isLinkUp; 1.652 +} 1.653 + 1.654 +NS_IMETHODIMP 1.655 +nsIOService::GetOffline(bool *offline) 1.656 +{ 1.657 + *offline = mOffline; 1.658 + return NS_OK; 1.659 +} 1.660 + 1.661 +NS_IMETHODIMP 1.662 +nsIOService::SetOffline(bool offline) 1.663 +{ 1.664 + // When someone wants to go online (!offline) after we got XPCOM shutdown 1.665 + // throw ERROR_NOT_AVAILABLE to prevent return to online state. 1.666 + if ((mShutdown || mOfflineForProfileChange) && !offline) 1.667 + return NS_ERROR_NOT_AVAILABLE; 1.668 + 1.669 + // SetOffline() may re-enter while it's shutting down services. 1.670 + // If that happens, save the most recent value and it will be 1.671 + // processed when the first SetOffline() call is done bringing 1.672 + // down the service. 1.673 + mSetOfflineValue = offline; 1.674 + if (mSettingOffline) { 1.675 + return NS_OK; 1.676 + } 1.677 + 1.678 + mSettingOffline = true; 1.679 + 1.680 + nsCOMPtr<nsIObserverService> observerService = 1.681 + mozilla::services::GetObserverService(); 1.682 + 1.683 + NS_ASSERTION(observerService, "The observer service should not be null"); 1.684 + 1.685 + if (XRE_GetProcessType() == GeckoProcessType_Default) { 1.686 + if (observerService) { 1.687 + (void)observerService->NotifyObservers(nullptr, 1.688 + NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC, offline ? 1.689 + MOZ_UTF16("true") : 1.690 + MOZ_UTF16("false")); 1.691 + } 1.692 + } 1.693 + 1.694 + nsIIOService *subject = static_cast<nsIIOService *>(this); 1.695 + while (mSetOfflineValue != mOffline) { 1.696 + offline = mSetOfflineValue; 1.697 + 1.698 + if (offline && !mOffline) { 1.699 + NS_NAMED_LITERAL_STRING(offlineString, NS_IOSERVICE_OFFLINE); 1.700 + mOffline = true; // indicate we're trying to shutdown 1.701 + 1.702 + // don't care if notifications fail 1.703 + if (observerService) 1.704 + observerService->NotifyObservers(subject, 1.705 + NS_IOSERVICE_GOING_OFFLINE_TOPIC, 1.706 + offlineString.get()); 1.707 + 1.708 + if (mDNSService) 1.709 + mDNSService->SetOffline(true); 1.710 + 1.711 + if (mSocketTransportService) 1.712 + mSocketTransportService->SetOffline(true); 1.713 + 1.714 + if (observerService) 1.715 + observerService->NotifyObservers(subject, 1.716 + NS_IOSERVICE_OFFLINE_STATUS_TOPIC, 1.717 + offlineString.get()); 1.718 + } 1.719 + else if (!offline && mOffline) { 1.720 + // go online 1.721 + if (mDNSService) { 1.722 + mDNSService->SetOffline(false); 1.723 + DebugOnly<nsresult> rv = mDNSService->Init(); 1.724 + NS_ASSERTION(NS_SUCCEEDED(rv), "DNS service init failed"); 1.725 + } 1.726 + InitializeSocketTransportService(); 1.727 + mOffline = false; // indicate success only AFTER we've 1.728 + // brought up the services 1.729 + 1.730 + // trigger a PAC reload when we come back online 1.731 + if (mProxyService) 1.732 + mProxyService->ReloadPAC(); 1.733 + 1.734 + // don't care if notification fails 1.735 + if (observerService) 1.736 + observerService->NotifyObservers(subject, 1.737 + NS_IOSERVICE_OFFLINE_STATUS_TOPIC, 1.738 + NS_LITERAL_STRING(NS_IOSERVICE_ONLINE).get()); 1.739 + } 1.740 + } 1.741 + 1.742 + // Don't notify here, as the above notifications (if used) suffice. 1.743 + if ((mShutdown || mOfflineForProfileChange) && mOffline) { 1.744 + // be sure to try and shutdown both (even if the first fails)... 1.745 + // shutdown dns service first, because it has callbacks for socket transport 1.746 + if (mDNSService) { 1.747 + DebugOnly<nsresult> rv = mDNSService->Shutdown(); 1.748 + NS_ASSERTION(NS_SUCCEEDED(rv), "DNS service shutdown failed"); 1.749 + } 1.750 + if (mSocketTransportService) { 1.751 + DebugOnly<nsresult> rv = mSocketTransportService->Shutdown(); 1.752 + NS_ASSERTION(NS_SUCCEEDED(rv), "socket transport service shutdown failed"); 1.753 + } 1.754 + } 1.755 + 1.756 + mSettingOffline = false; 1.757 + 1.758 + return NS_OK; 1.759 +} 1.760 + 1.761 + 1.762 +NS_IMETHODIMP 1.763 +nsIOService::AllowPort(int32_t inPort, const char *scheme, bool *_retval) 1.764 +{ 1.765 + int16_t port = inPort; 1.766 + if (port == -1) { 1.767 + *_retval = true; 1.768 + return NS_OK; 1.769 + } 1.770 + 1.771 + if (port == 0) { 1.772 + *_retval = false; 1.773 + return NS_OK; 1.774 + } 1.775 + 1.776 + // first check to see if the port is in our blacklist: 1.777 + int32_t badPortListCnt = mRestrictedPortList.Length(); 1.778 + for (int i=0; i<badPortListCnt; i++) 1.779 + { 1.780 + if (port == mRestrictedPortList[i]) 1.781 + { 1.782 + *_retval = false; 1.783 + 1.784 + // check to see if the protocol wants to override 1.785 + if (!scheme) 1.786 + return NS_OK; 1.787 + 1.788 + nsCOMPtr<nsIProtocolHandler> handler; 1.789 + nsresult rv = GetProtocolHandler(scheme, getter_AddRefs(handler)); 1.790 + if (NS_FAILED(rv)) return rv; 1.791 + 1.792 + // let the protocol handler decide 1.793 + return handler->AllowPort(port, scheme, _retval); 1.794 + } 1.795 + } 1.796 + 1.797 + *_retval = true; 1.798 + return NS_OK; 1.799 +} 1.800 + 1.801 +//////////////////////////////////////////////////////////////////////////////// 1.802 + 1.803 +void 1.804 +nsIOService::PrefsChanged(nsIPrefBranch *prefs, const char *pref) 1.805 +{ 1.806 + if (!prefs) return; 1.807 + 1.808 + // Look for extra ports to block 1.809 + if (!pref || strcmp(pref, PORT_PREF("banned")) == 0) 1.810 + ParsePortList(prefs, PORT_PREF("banned"), false); 1.811 + 1.812 + // ...as well as previous blocks to remove. 1.813 + if (!pref || strcmp(pref, PORT_PREF("banned.override")) == 0) 1.814 + ParsePortList(prefs, PORT_PREF("banned.override"), true); 1.815 + 1.816 + if (!pref || strcmp(pref, AUTODIAL_PREF) == 0) { 1.817 + bool enableAutodial = false; 1.818 + nsresult rv = prefs->GetBoolPref(AUTODIAL_PREF, &enableAutodial); 1.819 + // If pref not found, default to disabled. 1.820 + mAutoDialEnabled = enableAutodial; 1.821 + if (NS_SUCCEEDED(rv)) { 1.822 + if (mSocketTransportService) 1.823 + mSocketTransportService->SetAutodialEnabled(enableAutodial); 1.824 + } 1.825 + } 1.826 + 1.827 + if (!pref || strcmp(pref, MANAGE_OFFLINE_STATUS_PREF) == 0) { 1.828 + bool manage; 1.829 + if (mNetworkLinkServiceInitialized && 1.830 + NS_SUCCEEDED(prefs->GetBoolPref(MANAGE_OFFLINE_STATUS_PREF, 1.831 + &manage))) 1.832 + SetManageOfflineStatus(manage); 1.833 + } 1.834 + 1.835 + if (!pref || strcmp(pref, NECKO_BUFFER_CACHE_COUNT_PREF) == 0) { 1.836 + int32_t count; 1.837 + if (NS_SUCCEEDED(prefs->GetIntPref(NECKO_BUFFER_CACHE_COUNT_PREF, 1.838 + &count))) 1.839 + /* check for bogus values and default if we find such a value */ 1.840 + if (count > 0) 1.841 + gDefaultSegmentCount = count; 1.842 + } 1.843 + 1.844 + if (!pref || strcmp(pref, NECKO_BUFFER_CACHE_SIZE_PREF) == 0) { 1.845 + int32_t size; 1.846 + if (NS_SUCCEEDED(prefs->GetIntPref(NECKO_BUFFER_CACHE_SIZE_PREF, 1.847 + &size))) 1.848 + /* check for bogus values and default if we find such a value 1.849 + * the upper limit here is arbitrary. having a 1mb segment size 1.850 + * is pretty crazy. if you remove this, consider adding some 1.851 + * integer rollover test. 1.852 + */ 1.853 + if (size > 0 && size < 1024*1024) 1.854 + gDefaultSegmentSize = size; 1.855 + NS_WARN_IF_FALSE( (!(size & (size - 1))) , "network segment size is not a power of 2!"); 1.856 + } 1.857 +} 1.858 + 1.859 +void 1.860 +nsIOService::ParsePortList(nsIPrefBranch *prefBranch, const char *pref, bool remove) 1.861 +{ 1.862 + nsXPIDLCString portList; 1.863 + 1.864 + // Get a pref string and chop it up into a list of ports. 1.865 + prefBranch->GetCharPref(pref, getter_Copies(portList)); 1.866 + if (portList) { 1.867 + nsTArray<nsCString> portListArray; 1.868 + ParseString(portList, ',', portListArray); 1.869 + uint32_t index; 1.870 + for (index=0; index < portListArray.Length(); index++) { 1.871 + portListArray[index].StripWhitespace(); 1.872 + int32_t portBegin, portEnd; 1.873 + 1.874 + if (PR_sscanf(portListArray[index].get(), "%d-%d", &portBegin, &portEnd) == 2) { 1.875 + if ((portBegin < 65536) && (portEnd < 65536)) { 1.876 + int32_t curPort; 1.877 + if (remove) { 1.878 + for (curPort=portBegin; curPort <= portEnd; curPort++) 1.879 + mRestrictedPortList.RemoveElement(curPort); 1.880 + } else { 1.881 + for (curPort=portBegin; curPort <= portEnd; curPort++) 1.882 + mRestrictedPortList.AppendElement(curPort); 1.883 + } 1.884 + } 1.885 + } else { 1.886 + nsresult aErrorCode; 1.887 + int32_t port = portListArray[index].ToInteger(&aErrorCode); 1.888 + if (NS_SUCCEEDED(aErrorCode) && port < 65536) { 1.889 + if (remove) 1.890 + mRestrictedPortList.RemoveElement(port); 1.891 + else 1.892 + mRestrictedPortList.AppendElement(port); 1.893 + } 1.894 + } 1.895 + 1.896 + } 1.897 + } 1.898 +} 1.899 + 1.900 +void 1.901 +nsIOService::GetPrefBranch(nsIPrefBranch **result) 1.902 +{ 1.903 + *result = nullptr; 1.904 + CallGetService(NS_PREFSERVICE_CONTRACTID, result); 1.905 +} 1.906 + 1.907 +// nsIObserver interface 1.908 +NS_IMETHODIMP 1.909 +nsIOService::Observe(nsISupports *subject, 1.910 + const char *topic, 1.911 + const char16_t *data) 1.912 +{ 1.913 + if (!strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) { 1.914 + nsCOMPtr<nsIPrefBranch> prefBranch = do_QueryInterface(subject); 1.915 + if (prefBranch) 1.916 + PrefsChanged(prefBranch, NS_ConvertUTF16toUTF8(data).get()); 1.917 + } 1.918 + else if (!strcmp(topic, kProfileChangeNetTeardownTopic)) { 1.919 + if (!mOffline) { 1.920 + mOfflineForProfileChange = true; 1.921 + SetOffline(true); 1.922 + } 1.923 + } 1.924 + else if (!strcmp(topic, kProfileChangeNetRestoreTopic)) { 1.925 + if (mOfflineForProfileChange) { 1.926 + mOfflineForProfileChange = false; 1.927 + if (!mManageOfflineStatus || 1.928 + NS_FAILED(TrackNetworkLinkStatusForOffline())) { 1.929 + SetOffline(false); 1.930 + } 1.931 + } 1.932 + } 1.933 + else if (!strcmp(topic, kProfileDoChange)) { 1.934 + if (data && NS_LITERAL_STRING("startup").Equals(data)) { 1.935 + // Lazy initialization of network link service (see bug 620472) 1.936 + InitializeNetworkLinkService(); 1.937 + // Set up the initilization flag regardless the actuall result. 1.938 + // If we fail here, we will fail always on. 1.939 + mNetworkLinkServiceInitialized = true; 1.940 + // And now reflect the preference setting 1.941 + nsCOMPtr<nsIPrefBranch> prefBranch; 1.942 + GetPrefBranch(getter_AddRefs(prefBranch)); 1.943 + PrefsChanged(prefBranch, MANAGE_OFFLINE_STATUS_PREF); 1.944 + } 1.945 + } 1.946 + else if (!strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) { 1.947 + // Remember we passed XPCOM shutdown notification to prevent any 1.948 + // changes of the offline status from now. We must not allow going 1.949 + // online after this point. 1.950 + mShutdown = true; 1.951 + 1.952 + SetOffline(true); 1.953 + 1.954 + // Break circular reference. 1.955 + mProxyService = nullptr; 1.956 + } 1.957 + else if (!strcmp(topic, NS_NETWORK_LINK_TOPIC)) { 1.958 + if (!mOfflineForProfileChange && mManageOfflineStatus) { 1.959 + TrackNetworkLinkStatusForOffline(); 1.960 + } 1.961 + } 1.962 + 1.963 + return NS_OK; 1.964 +} 1.965 + 1.966 +// nsINetUtil interface 1.967 +NS_IMETHODIMP 1.968 +nsIOService::ParseContentType(const nsACString &aTypeHeader, 1.969 + nsACString &aCharset, 1.970 + bool *aHadCharset, 1.971 + nsACString &aContentType) 1.972 +{ 1.973 + net_ParseContentType(aTypeHeader, aContentType, aCharset, aHadCharset); 1.974 + return NS_OK; 1.975 +} 1.976 + 1.977 +NS_IMETHODIMP 1.978 +nsIOService::ProtocolHasFlags(nsIURI *uri, 1.979 + uint32_t flags, 1.980 + bool *result) 1.981 +{ 1.982 + NS_ENSURE_ARG(uri); 1.983 + 1.984 + *result = false; 1.985 + nsAutoCString scheme; 1.986 + nsresult rv = uri->GetScheme(scheme); 1.987 + NS_ENSURE_SUCCESS(rv, rv); 1.988 + 1.989 + uint32_t protocolFlags; 1.990 + rv = GetProtocolFlags(scheme.get(), &protocolFlags); 1.991 + 1.992 + if (NS_SUCCEEDED(rv)) { 1.993 + *result = (protocolFlags & flags) == flags; 1.994 + } 1.995 + 1.996 + return rv; 1.997 +} 1.998 + 1.999 +NS_IMETHODIMP 1.1000 +nsIOService::URIChainHasFlags(nsIURI *uri, 1.1001 + uint32_t flags, 1.1002 + bool *result) 1.1003 +{ 1.1004 + nsresult rv = ProtocolHasFlags(uri, flags, result); 1.1005 + NS_ENSURE_SUCCESS(rv, rv); 1.1006 + 1.1007 + if (*result) { 1.1008 + return rv; 1.1009 + } 1.1010 + 1.1011 + // Dig deeper into the chain. Note that this is not a do/while loop to 1.1012 + // avoid the extra addref/release on |uri| in the common (non-nested) case. 1.1013 + nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(uri); 1.1014 + while (nestedURI) { 1.1015 + nsCOMPtr<nsIURI> innerURI; 1.1016 + rv = nestedURI->GetInnerURI(getter_AddRefs(innerURI)); 1.1017 + NS_ENSURE_SUCCESS(rv, rv); 1.1018 + 1.1019 + rv = ProtocolHasFlags(innerURI, flags, result); 1.1020 + 1.1021 + if (*result) { 1.1022 + return rv; 1.1023 + } 1.1024 + 1.1025 + nestedURI = do_QueryInterface(innerURI); 1.1026 + } 1.1027 + 1.1028 + return rv; 1.1029 +} 1.1030 + 1.1031 +NS_IMETHODIMP 1.1032 +nsIOService::ToImmutableURI(nsIURI* uri, nsIURI** result) 1.1033 +{ 1.1034 + if (!uri) { 1.1035 + *result = nullptr; 1.1036 + return NS_OK; 1.1037 + } 1.1038 + 1.1039 + nsresult rv = NS_EnsureSafeToReturn(uri, result); 1.1040 + NS_ENSURE_SUCCESS(rv, rv); 1.1041 + 1.1042 + NS_TryToSetImmutable(*result); 1.1043 + return NS_OK; 1.1044 +} 1.1045 + 1.1046 +NS_IMETHODIMP 1.1047 +nsIOService::NewSimpleNestedURI(nsIURI* aURI, nsIURI** aResult) 1.1048 +{ 1.1049 + NS_ENSURE_ARG(aURI); 1.1050 + 1.1051 + nsCOMPtr<nsIURI> safeURI; 1.1052 + nsresult rv = NS_EnsureSafeToReturn(aURI, getter_AddRefs(safeURI)); 1.1053 + NS_ENSURE_SUCCESS(rv, rv); 1.1054 + 1.1055 + NS_IF_ADDREF(*aResult = new nsSimpleNestedURI(safeURI)); 1.1056 + return *aResult ? NS_OK : NS_ERROR_OUT_OF_MEMORY; 1.1057 +} 1.1058 + 1.1059 +NS_IMETHODIMP 1.1060 +nsIOService::SetManageOfflineStatus(bool aManage) { 1.1061 + nsresult rv = NS_OK; 1.1062 + 1.1063 + // SetManageOfflineStatus must throw when we fail to go from non-managed 1.1064 + // to managed. Usually because there is no link monitoring service 1.1065 + // available. Failure to do this switch is detected by a failure of 1.1066 + // TrackNetworkLinkStatusForOffline(). When there is no network link 1.1067 + // available during call to InitializeNetworkLinkService(), application is 1.1068 + // put to offline mode. And when we change mMangeOfflineStatus to false 1.1069 + // on the next line we get stuck on being offline even though the link 1.1070 + // becomes later available. 1.1071 + bool wasManaged = mManageOfflineStatus; 1.1072 + mManageOfflineStatus = aManage; 1.1073 + 1.1074 + InitializeNetworkLinkService(); 1.1075 + 1.1076 + if (mManageOfflineStatus && !wasManaged) { 1.1077 + rv = TrackNetworkLinkStatusForOffline(); 1.1078 + if (NS_FAILED(rv)) 1.1079 + mManageOfflineStatus = false; 1.1080 + } 1.1081 + return rv; 1.1082 +} 1.1083 + 1.1084 +NS_IMETHODIMP 1.1085 +nsIOService::GetManageOfflineStatus(bool* aManage) { 1.1086 + *aManage = mManageOfflineStatus; 1.1087 + return NS_OK; 1.1088 +} 1.1089 + 1.1090 +nsresult 1.1091 +nsIOService::TrackNetworkLinkStatusForOffline() 1.1092 +{ 1.1093 + NS_ASSERTION(mManageOfflineStatus, 1.1094 + "Don't call this unless we're managing the offline status"); 1.1095 + if (!mNetworkLinkService) 1.1096 + return NS_ERROR_FAILURE; 1.1097 + 1.1098 + if (mShutdown) 1.1099 + return NS_ERROR_NOT_AVAILABLE; 1.1100 + 1.1101 + // check to make sure this won't collide with Autodial 1.1102 + if (mSocketTransportService) { 1.1103 + bool autodialEnabled = false; 1.1104 + mSocketTransportService->GetAutodialEnabled(&autodialEnabled); 1.1105 + // If autodialing-on-link-down is enabled, check if the OS auto dial 1.1106 + // option is set to always autodial. If so, then we are 1.1107 + // always up for the purposes of offline management. 1.1108 + if (autodialEnabled) { 1.1109 +#if defined(XP_WIN) 1.1110 + // On Windows, we should first check with the OS 1.1111 + // to see if autodial is enabled. If it is 1.1112 + // enabled then we are allowed to manage the 1.1113 + // offline state. 1.1114 + if(nsNativeConnectionHelper::IsAutodialEnabled()) 1.1115 + return SetOffline(false); 1.1116 +#else 1.1117 + return SetOffline(false); 1.1118 +#endif 1.1119 + } 1.1120 + } 1.1121 + 1.1122 + bool isUp; 1.1123 + nsresult rv = mNetworkLinkService->GetIsLinkUp(&isUp); 1.1124 + NS_ENSURE_SUCCESS(rv, rv); 1.1125 + return SetOffline(!isUp); 1.1126 +} 1.1127 + 1.1128 +NS_IMETHODIMP 1.1129 +nsIOService::EscapeString(const nsACString& aString, 1.1130 + uint32_t aEscapeType, 1.1131 + nsACString& aResult) 1.1132 +{ 1.1133 + NS_ENSURE_ARG_MAX(aEscapeType, 4); 1.1134 + 1.1135 + nsAutoCString stringCopy(aString); 1.1136 + nsCString result; 1.1137 + 1.1138 + if (!NS_Escape(stringCopy, result, (nsEscapeMask) aEscapeType)) 1.1139 + return NS_ERROR_OUT_OF_MEMORY; 1.1140 + 1.1141 + aResult.Assign(result); 1.1142 + 1.1143 + return NS_OK; 1.1144 +} 1.1145 + 1.1146 +NS_IMETHODIMP 1.1147 +nsIOService::EscapeURL(const nsACString &aStr, 1.1148 + uint32_t aFlags, nsACString &aResult) 1.1149 +{ 1.1150 + aResult.Truncate(); 1.1151 + NS_EscapeURL(aStr.BeginReading(), aStr.Length(), 1.1152 + aFlags | esc_AlwaysCopy, aResult); 1.1153 + return NS_OK; 1.1154 +} 1.1155 + 1.1156 +NS_IMETHODIMP 1.1157 +nsIOService::UnescapeString(const nsACString &aStr, 1.1158 + uint32_t aFlags, nsACString &aResult) 1.1159 +{ 1.1160 + aResult.Truncate(); 1.1161 + NS_UnescapeURL(aStr.BeginReading(), aStr.Length(), 1.1162 + aFlags | esc_AlwaysCopy, aResult); 1.1163 + return NS_OK; 1.1164 +} 1.1165 + 1.1166 +NS_IMETHODIMP 1.1167 +nsIOService::ExtractCharsetFromContentType(const nsACString &aTypeHeader, 1.1168 + nsACString &aCharset, 1.1169 + int32_t *aCharsetStart, 1.1170 + int32_t *aCharsetEnd, 1.1171 + bool *aHadCharset) 1.1172 +{ 1.1173 + nsAutoCString ignored; 1.1174 + net_ParseContentType(aTypeHeader, ignored, aCharset, aHadCharset, 1.1175 + aCharsetStart, aCharsetEnd); 1.1176 + if (*aHadCharset && *aCharsetStart == *aCharsetEnd) { 1.1177 + *aHadCharset = false; 1.1178 + } 1.1179 + return NS_OK; 1.1180 +} 1.1181 + 1.1182 +// nsISpeculativeConnect 1.1183 +class IOServiceProxyCallback MOZ_FINAL : public nsIProtocolProxyCallback 1.1184 +{ 1.1185 +public: 1.1186 + NS_DECL_ISUPPORTS 1.1187 + NS_DECL_NSIPROTOCOLPROXYCALLBACK 1.1188 + 1.1189 + IOServiceProxyCallback(nsIInterfaceRequestor *aCallbacks, 1.1190 + nsIOService *aIOService) 1.1191 + : mCallbacks(aCallbacks) 1.1192 + , mIOService(aIOService) 1.1193 + { } 1.1194 + 1.1195 +private: 1.1196 + nsRefPtr<nsIInterfaceRequestor> mCallbacks; 1.1197 + nsRefPtr<nsIOService> mIOService; 1.1198 +}; 1.1199 + 1.1200 +NS_IMPL_ISUPPORTS(IOServiceProxyCallback, nsIProtocolProxyCallback) 1.1201 + 1.1202 +NS_IMETHODIMP 1.1203 +IOServiceProxyCallback::OnProxyAvailable(nsICancelable *request, nsIChannel *channel, 1.1204 + nsIProxyInfo *pi, nsresult status) 1.1205 +{ 1.1206 + // Checking proxy status for speculative connect 1.1207 + nsAutoCString type; 1.1208 + if (NS_SUCCEEDED(status) && pi && 1.1209 + NS_SUCCEEDED(pi->GetType(type)) && 1.1210 + !type.EqualsLiteral("direct")) { 1.1211 + // proxies dont do speculative connect 1.1212 + return NS_OK; 1.1213 + } 1.1214 + 1.1215 + nsCOMPtr<nsIURI> uri; 1.1216 + nsresult rv = channel->GetURI(getter_AddRefs(uri)); 1.1217 + if (NS_FAILED(rv)) 1.1218 + return NS_OK; 1.1219 + 1.1220 + nsAutoCString scheme; 1.1221 + rv = uri->GetScheme(scheme); 1.1222 + if (NS_FAILED(rv)) 1.1223 + return NS_OK; 1.1224 + 1.1225 + nsCOMPtr<nsIProtocolHandler> handler; 1.1226 + rv = mIOService->GetProtocolHandler(scheme.get(), 1.1227 + getter_AddRefs(handler)); 1.1228 + if (NS_FAILED(rv)) 1.1229 + return NS_OK; 1.1230 + 1.1231 + nsCOMPtr<nsISpeculativeConnect> speculativeHandler = 1.1232 + do_QueryInterface(handler); 1.1233 + if (!speculativeHandler) 1.1234 + return NS_OK; 1.1235 + 1.1236 + speculativeHandler->SpeculativeConnect(uri, 1.1237 + mCallbacks); 1.1238 + return NS_OK; 1.1239 +} 1.1240 + 1.1241 +NS_IMETHODIMP 1.1242 +nsIOService::SpeculativeConnect(nsIURI *aURI, 1.1243 + nsIInterfaceRequestor *aCallbacks) 1.1244 +{ 1.1245 + // Check for proxy information. If there is a proxy configured then a 1.1246 + // speculative connect should not be performed because the potential 1.1247 + // reward is slim with tcp peers closely located to the browser. 1.1248 + nsresult rv; 1.1249 + nsCOMPtr<nsIProtocolProxyService> pps = 1.1250 + do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv); 1.1251 + if (NS_FAILED(rv)) 1.1252 + return rv; 1.1253 + 1.1254 + nsCOMPtr<nsIChannel> channel; 1.1255 + rv = NewChannelFromURI(aURI, getter_AddRefs(channel)); 1.1256 + if (NS_FAILED(rv)) 1.1257 + return rv; 1.1258 + 1.1259 + nsCOMPtr<nsICancelable> cancelable; 1.1260 + nsRefPtr<IOServiceProxyCallback> callback = 1.1261 + new IOServiceProxyCallback(aCallbacks, this); 1.1262 + return pps->AsyncResolve(channel, 0, callback, getter_AddRefs(cancelable)); 1.1263 +}