netwerk/base/src/nsIOService.cpp

changeset 0
6474c204b198
     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 +}

mercurial