Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/netwerk/base/nsIOService.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/* vim:set ts=4 sw=4 cindent et: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "mozilla/DebugOnly.h"
8
9
#include "nsIOService.h"
10
#include "nsIProtocolHandler.h"
11
#include "nsIFileProtocolHandler.h"
12
#include "nscore.h"
13
#include "nsIURI.h"
14
#include "prprf.h"
15
#include "nsIErrorService.h"
16
#include "netCore.h"
17
#include "nsIObserverService.h"
18
#include "nsIPrefService.h"
19
#include "nsXPCOM.h"
20
#include "nsIProxiedProtocolHandler.h"
21
#include "nsIProxyInfo.h"
22
#include "nsEscape.h"
23
#include "nsNetUtil.h"
24
#include "nsNetCID.h"
25
#include "nsCRT.h"
26
#include "nsSecCheckWrapChannel.h"
27
#include "nsSimpleNestedURI.h"
28
#include "nsTArray.h"
29
#include "nsIConsoleService.h"
30
#include "nsIUploadChannel2.h"
31
#include "nsXULAppAPI.h"
32
#include "nsIScriptSecurityManager.h"
33
#include "nsIProtocolProxyCallback.h"
34
#include "nsICancelable.h"
35
#include "nsINetworkLinkService.h"
36
#include "nsPISocketTransportService.h"
37
#include "nsAsyncRedirectVerifyHelper.h"
38
#include "nsURLHelper.h"
39
#include "nsIProtocolProxyService2.h"
40
#include "MainThreadUtils.h"
41
#include "nsINode.h"
42
#include "nsIWidget.h"
43
#include "nsThreadUtils.h"
44
#include "mozilla/LoadInfo.h"
45
#include "mozilla/net/NeckoCommon.h"
46
#include "mozilla/Services.h"
47
#include "mozilla/Telemetry.h"
48
#include "mozilla/net/DNS.h"
49
#include "mozilla/ipc/URIUtils.h"
50
#include "mozilla/net/NeckoChild.h"
51
#include "mozilla/net/NeckoParent.h"
52
#include "mozilla/dom/ClientInfo.h"
53
#include "mozilla/dom/ContentParent.h"
54
#include "mozilla/dom/ServiceWorkerDescriptor.h"
55
#include "mozilla/net/CaptivePortalService.h"
56
#include "mozilla/Unused.h"
57
#include "ReferrerPolicy.h"
58
#include "nsContentSecurityManager.h"
59
#include "nsContentUtils.h"
60
61
namespace mozilla {
62
namespace net {
63
64
using mozilla::Maybe;
65
using mozilla::dom::ClientInfo;
66
using mozilla::dom::ServiceWorkerDescriptor;
67
68
6
#define PORT_PREF_PREFIX           "network.security.ports."
69
6
#define PORT_PREF(x)               PORT_PREF_PREFIX x
70
0
#define MANAGE_OFFLINE_STATUS_PREF "network.manage-offline-status"
71
3
#define OFFLINE_MIRRORS_CONNECTIVITY "network.offline-mirrors-connectivity"
72
73
// Nb: these have been misnomers since bug 715770 removed the buffer cache.
74
// "network.segment.count" and "network.segment.size" would be better names,
75
// but the old names are still used to preserve backward compatibility.
76
0
#define NECKO_BUFFER_CACHE_COUNT_PREF "network.buffer.cache.count"
77
0
#define NECKO_BUFFER_CACHE_SIZE_PREF  "network.buffer.cache.size"
78
3
#define NETWORK_NOTIFY_CHANGED_PREF   "network.notify.changed"
79
3
#define NETWORK_CAPTIVE_PORTAL_PREF   "network.captive-portal-service.enabled"
80
81
3.05M
#define MAX_RECURSION_COUNT 50
82
83
nsIOService* gIOService;
84
static bool gHasWarnedUploadChannel2;
85
static bool gCaptivePortalEnabled = false;
86
static LazyLogModule gIOServiceLog("nsIOService");
87
#undef LOG
88
9
#define LOG(args)     MOZ_LOG(gIOServiceLog, LogLevel::Debug, args)
89
90
// A general port blacklist.  Connections to these ports will not be allowed
91
// unless the protocol overrides.
92
//
93
// TODO: I am sure that there are more ports to be added.
94
//       This cut is based on the classic mozilla codebase
95
96
int16_t gBadPortList[] = {
97
  1,    // tcpmux
98
  7,    // echo
99
  9,    // discard
100
  11,   // systat
101
  13,   // daytime
102
  15,   // netstat
103
  17,   // qotd
104
  19,   // chargen
105
  20,   // ftp-data
106
  21,   // ftp
107
  22,   // ssh
108
  23,   // telnet
109
  25,   // smtp
110
  37,   // time
111
  42,   // name
112
  43,   // nicname
113
  53,   // domain
114
  77,   // priv-rjs
115
  79,   // finger
116
  87,   // ttylink
117
  95,   // supdup
118
  101,  // hostriame
119
  102,  // iso-tsap
120
  103,  // gppitnp
121
  104,  // acr-nema
122
  109,  // pop2
123
  110,  // pop3
124
  111,  // sunrpc
125
  113,  // auth
126
  115,  // sftp
127
  117,  // uucp-path
128
  119,  // nntp
129
  123,  // ntp
130
  135,  // loc-srv / epmap
131
  139,  // netbios
132
  143,  // imap2
133
  179,  // bgp
134
  389,  // ldap
135
  427,  // afp (alternate)
136
  465,  // smtp (alternate)
137
  512,  // print / exec
138
  513,  // login
139
  514,  // shell
140
  515,  // printer
141
  526,  // tempo
142
  530,  // courier
143
  531,  // chat
144
  532,  // netnews
145
  540,  // uucp
146
  548,  // afp
147
  556,  // remotefs
148
  563,  // nntp+ssl
149
  587,  // smtp (outgoing)
150
  601,  // syslog-conn
151
  636,  // ldap+ssl
152
  993,  // imap+ssl
153
  995,  // pop3+ssl
154
  2049, // nfs
155
  3659, // apple-sasl
156
  4045, // lockd
157
  6000, // x11
158
  6665, // irc (alternate)
159
  6666, // irc (alternate)
160
  6667, // irc (default)
161
  6668, // irc (alternate)
162
  6669, // irc (alternate)
163
  6697, // irc+tls
164
  0,    // Sentinel value: This MUST be zero
165
};
166
167
static const char kProfileChangeNetTeardownTopic[] = "profile-change-net-teardown";
168
static const char kProfileChangeNetRestoreTopic[] = "profile-change-net-restore";
169
static const char kProfileDoChange[] = "profile-do-change";
170
171
// Necko buffer defaults
172
uint32_t   nsIOService::gDefaultSegmentSize = 4096;
173
uint32_t   nsIOService::gDefaultSegmentCount = 24;
174
175
bool nsIOService::sIsDataURIUniqueOpaqueOrigin = false;
176
bool nsIOService::sBlockToplevelDataUriNavigations = false;
177
bool nsIOService::sBlockFTPSubresources = false;
178
179
////////////////////////////////////////////////////////////////////////////////
180
181
nsIOService::nsIOService()
182
    : mOffline(true)
183
    , mOfflineForProfileChange(false)
184
    , mManageLinkStatus(false)
185
    , mConnectivity(true)
186
    , mOfflineMirrorsConnectivity(true)
187
    , mSettingOffline(false)
188
    , mSetOfflineValue(false)
189
    , mShutdown(false)
190
    , mHttpHandlerAlreadyShutingDown(false)
191
    , mNetworkLinkServiceInitialized(false)
192
    , mChannelEventSinks(NS_CHANNEL_EVENT_SINK_CATEGORY)
193
    , mNetworkNotifyChanged(true)
194
    , mTotalRequests(0)
195
    , mCacheWon(0)
196
    , mNetWon(0)
197
    , mLastOfflineStateChange(PR_IntervalNow())
198
    , mLastConnectivityChange(PR_IntervalNow())
199
    , mLastNetworkLinkChange(PR_IntervalNow())
200
    , mNetTearingDownStarted(0)
201
3
{
202
3
}
203
204
static const char* gCallbackPrefs[] = {
205
    PORT_PREF_PREFIX,
206
    MANAGE_OFFLINE_STATUS_PREF,
207
    NECKO_BUFFER_CACHE_COUNT_PREF,
208
    NECKO_BUFFER_CACHE_SIZE_PREF,
209
    NETWORK_NOTIFY_CHANGED_PREF,
210
    NETWORK_CAPTIVE_PORTAL_PREF,
211
    nullptr,
212
};
213
214
nsresult
215
nsIOService::Init()
216
3
{
217
3
    // XXX hack until xpidl supports error info directly (bug 13423)
218
3
    nsCOMPtr<nsIErrorService> errorService = do_GetService(NS_ERRORSERVICE_CONTRACTID);
219
3
    if (errorService) {
220
3
        errorService->RegisterErrorStringBundle(NS_ERROR_MODULE_NETWORK, NECKO_MSGS_URL);
221
3
    }
222
3
    else
223
3
        NS_WARNING("failed to get error service");
224
3
225
3
    InitializeCaptivePortalService();
226
3
227
3
    // setup our bad port list stuff
228
204
    for(int i=0; gBadPortList[i]; i++)
229
201
        mRestrictedPortList.AppendElement(gBadPortList[i]);
230
3
231
3
    // Further modifications to the port list come from prefs
232
3
    Preferences::RegisterPrefixCallbacks(
233
3
        PREF_CHANGE_METHOD(nsIOService::PrefsChanged),
234
3
        gCallbackPrefs, this);
235
3
    PrefsChanged();
236
3
237
3
    // Register for profile change notifications
238
3
    nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
239
3
    if (observerService) {
240
3
        observerService->AddObserver(this, kProfileChangeNetTeardownTopic, true);
241
3
        observerService->AddObserver(this, kProfileChangeNetRestoreTopic, true);
242
3
        observerService->AddObserver(this, kProfileDoChange, true);
243
3
        observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, true);
244
3
        observerService->AddObserver(this, NS_NETWORK_LINK_TOPIC, true);
245
3
        observerService->AddObserver(this, NS_WIDGET_WAKE_OBSERVER_TOPIC, true);
246
3
    }
247
3
    else
248
3
        NS_WARNING("failed to get observer service");
249
3
250
3
    Preferences::AddBoolVarCache(&sIsDataURIUniqueOpaqueOrigin,
251
3
                                 "security.data_uri.unique_opaque_origin", false);
252
3
    Preferences::AddBoolVarCache(&sBlockToplevelDataUriNavigations,
253
3
                                 "security.data_uri.block_toplevel_data_uri_navigations", false);
254
3
    Preferences::AddBoolVarCache(&sBlockFTPSubresources,
255
3
                                 "security.block_ftp_subresources", true);
256
3
    Preferences::AddBoolVarCache(&mOfflineMirrorsConnectivity, OFFLINE_MIRRORS_CONNECTIVITY, true);
257
3
258
3
    gIOService = this;
259
3
260
3
    InitializeNetworkLinkService();
261
3
    InitializeProtocolProxyService();
262
3
263
3
    SetOffline(false);
264
3
265
3
    return NS_OK;
266
3
}
267
268
269
nsIOService::~nsIOService()
270
0
{
271
0
    if (gIOService) {
272
0
        MOZ_ASSERT(gIOService == this);
273
0
        gIOService = nullptr;
274
0
    }
275
0
}
276
277
nsresult
278
nsIOService::InitializeCaptivePortalService()
279
3
{
280
3
    if (XRE_GetProcessType() != GeckoProcessType_Default) {
281
0
        // We only initalize a captive portal service in the main process
282
0
        return NS_OK;
283
0
    }
284
3
285
3
    mCaptivePortalService = do_GetService(NS_CAPTIVEPORTAL_CID);
286
3
    if (mCaptivePortalService) {
287
3
        return static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Initialize();
288
3
    }
289
0
290
0
    return NS_OK;
291
0
}
292
293
nsresult
294
nsIOService::InitializeSocketTransportService()
295
3
{
296
3
    nsresult rv = NS_OK;
297
3
298
3
    if (!mSocketTransportService) {
299
3
        mSocketTransportService = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
300
3
        if (NS_FAILED(rv)) {
301
0
            NS_WARNING("failed to get socket transport service");
302
0
        }
303
3
    }
304
3
305
3
    if (mSocketTransportService) {
306
3
        rv = mSocketTransportService->Init();
307
3
        NS_ASSERTION(NS_SUCCEEDED(rv), "socket transport service init failed");
308
3
        mSocketTransportService->SetOffline(false);
309
3
    }
310
3
311
3
    return rv;
312
3
}
313
314
nsresult
315
nsIOService::InitializeNetworkLinkService()
316
3
{
317
3
    nsresult rv = NS_OK;
318
3
319
3
    if (mNetworkLinkServiceInitialized)
320
0
        return rv;
321
3
322
3
    if (!NS_IsMainThread()) {
323
0
        NS_WARNING("Network link service should be created on main thread");
324
0
        return NS_ERROR_FAILURE;
325
0
    }
326
3
327
3
    // go into managed mode if we can, and chrome process
328
3
    if (XRE_IsParentProcess())
329
3
    {
330
3
        mNetworkLinkService = do_GetService(NS_NETWORK_LINK_SERVICE_CONTRACTID, &rv);
331
3
    }
332
3
333
3
    if (mNetworkLinkService) {
334
3
        mNetworkLinkServiceInitialized = true;
335
3
    }
336
3
337
3
    // After initializing the networkLinkService, query the connectivity state
338
3
    OnNetworkLinkEvent(NS_NETWORK_LINK_DATA_UNKNOWN);
339
3
340
3
    return rv;
341
3
}
342
343
nsresult
344
nsIOService::InitializeProtocolProxyService()
345
3
{
346
3
    nsresult rv = NS_OK;
347
3
348
3
    if (XRE_IsParentProcess()) {
349
3
        // for early-initialization
350
3
        Unused << do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv);
351
3
    }
352
3
353
3
    return rv;
354
3
}
355
356
already_AddRefed<nsIOService>
357
3
nsIOService::GetInstance() {
358
3
    if (!gIOService) {
359
3
        RefPtr<nsIOService> ios = new nsIOService();
360
3
        if (NS_SUCCEEDED(ios->Init())) {
361
3
            MOZ_ASSERT(gIOService == ios.get());
362
3
            return ios.forget();
363
3
        }
364
0
    }
365
0
    return do_AddRef(gIOService);
366
0
}
367
368
NS_IMPL_ISUPPORTS(nsIOService,
369
                  nsIIOService,
370
                  nsINetUtil,
371
                  nsISpeculativeConnect,
372
                  nsIObserver,
373
                  nsIIOServiceInternal,
374
                  nsISupportsWeakReference)
375
376
////////////////////////////////////////////////////////////////////////////////
377
378
nsresult
379
nsIOService::RecheckCaptivePortal()
380
0
{
381
0
  MOZ_ASSERT(NS_IsMainThread(), "Must be called on the main thread");
382
0
  if (!mCaptivePortalService) {
383
0
    return NS_OK;
384
0
  }
385
0
  nsCOMPtr<nsIRunnable> task =
386
0
    NewRunnableMethod("nsIOService::RecheckCaptivePortal",
387
0
                      mCaptivePortalService,
388
0
                      &nsICaptivePortalService::RecheckCaptivePortal);
389
0
  return NS_DispatchToMainThread(task);
390
0
}
391
392
nsresult
393
nsIOService::RecheckCaptivePortalIfLocalRedirect(nsIChannel* newChan)
394
0
{
395
0
    nsresult rv;
396
0
397
0
    if (!mCaptivePortalService) {
398
0
        return NS_OK;
399
0
    }
400
0
401
0
    nsCOMPtr<nsIURI> uri;
402
0
    rv = newChan->GetURI(getter_AddRefs(uri));
403
0
    if (NS_FAILED(rv)) {
404
0
        return rv;
405
0
    }
406
0
407
0
    nsCString host;
408
0
    rv = uri->GetHost(host);
409
0
    if (NS_FAILED(rv)) {
410
0
        return rv;
411
0
    }
412
0
413
0
    PRNetAddr prAddr;
414
0
    if (PR_StringToNetAddr(host.BeginReading(), &prAddr) != PR_SUCCESS) {
415
0
        // The redirect wasn't to an IP literal, so there's probably no need
416
0
        // to trigger the captive portal detection right now. It can wait.
417
0
        return NS_OK;
418
0
    }
419
0
420
0
    NetAddr netAddr;
421
0
    PRNetAddrToNetAddr(&prAddr, &netAddr);
422
0
    if (IsIPAddrLocal(&netAddr)) {
423
0
        // Redirects to local IP addresses are probably captive portals
424
0
        RecheckCaptivePortal();
425
0
    }
426
0
427
0
    return NS_OK;
428
0
}
429
430
nsresult
431
nsIOService::AsyncOnChannelRedirect(nsIChannel* oldChan, nsIChannel* newChan,
432
                                    uint32_t flags,
433
                                    nsAsyncRedirectVerifyHelper *helper)
434
0
{
435
0
    // If a redirect to a local network address occurs, then chances are we
436
0
    // are in a captive portal, so we trigger a recheck.
437
0
    RecheckCaptivePortalIfLocalRedirect(newChan);
438
0
439
0
    // This is silly. I wish there was a simpler way to get at the global
440
0
    // reference of the contentSecurityManager. But it lives in the XPCOM
441
0
    // service registry.
442
0
    nsCOMPtr<nsIChannelEventSink> sink =
443
0
        do_GetService(NS_CONTENTSECURITYMANAGER_CONTRACTID);
444
0
    if (sink) {
445
0
        nsresult rv = helper->DelegateOnChannelRedirect(sink, oldChan,
446
0
                                                        newChan, flags);
447
0
        if (NS_FAILED(rv))
448
0
            return rv;
449
0
    }
450
0
451
0
    // Finally, our category
452
0
    nsCOMArray<nsIChannelEventSink> entries;
453
0
    mChannelEventSinks.GetEntries(entries);
454
0
    int32_t len = entries.Count();
455
0
    for (int32_t i = 0; i < len; ++i) {
456
0
        nsresult rv = helper->DelegateOnChannelRedirect(entries[i], oldChan,
457
0
                                                        newChan, flags);
458
0
        if (NS_FAILED(rv))
459
0
            return rv;
460
0
    }
461
0
    return NS_OK;
462
0
}
463
464
nsresult
465
nsIOService::CacheProtocolHandler(const char *scheme, nsIProtocolHandler *handler)
466
1.64M
{
467
1.64M
    MOZ_ASSERT(NS_IsMainThread());
468
1.64M
469
21.4M
    for (unsigned int i=0; i<NS_N(gScheme); i++)
470
19.7M
    {
471
19.7M
        if (!nsCRT::strcasecmp(scheme, gScheme[i]))
472
17
        {
473
17
            nsresult rv;
474
17
            NS_ASSERTION(!mWeakHandler[i], "Protocol handler already cached");
475
17
            // Make sure the handler supports weak references.
476
17
            nsCOMPtr<nsISupportsWeakReference> factoryPtr = do_QueryInterface(handler, &rv);
477
17
            if (!factoryPtr)
478
0
            {
479
0
                // Don't cache handlers that don't support weak reference as
480
0
                // there is real danger of a circular reference.
481
#ifdef DEBUG_dp
482
                printf("DEBUG: %s protcol handler doesn't support weak ref. Not cached.\n", scheme);
483
#endif /* DEBUG_dp */
484
                return NS_ERROR_FAILURE;
485
0
            }
486
17
            mWeakHandler[i] = do_GetWeakReference(handler);
487
17
            return NS_OK;
488
17
        }
489
19.7M
    }
490
1.64M
    return NS_ERROR_FAILURE;
491
1.64M
}
492
493
nsresult
494
nsIOService::GetCachedProtocolHandler(const char *scheme, nsIProtocolHandler **result, uint32_t start, uint32_t end)
495
3.06M
{
496
3.06M
    MOZ_ASSERT(NS_IsMainThread());
497
3.06M
498
3.06M
    uint32_t len = end - start - 1;
499
28.5M
    for (unsigned int i=0; i<NS_N(gScheme); i++)
500
26.6M
    {
501
26.6M
        if (!mWeakHandler[i])
502
5.81M
            continue;
503
20.8M
504
20.8M
        // handle unterminated strings
505
20.8M
        // start is inclusive, end is exclusive, len = end - start - 1
506
20.8M
        if (end ? (!nsCRT::strncasecmp(scheme + start, gScheme[i], len)
507
0
                   && gScheme[i][len] == '\0')
508
20.8M
                : (!nsCRT::strcasecmp(scheme, gScheme[i])))
509
1.12M
        {
510
1.12M
            return CallQueryReferent(mWeakHandler[i].get(), result);
511
1.12M
        }
512
20.8M
    }
513
3.06M
    return NS_ERROR_FAILURE;
514
3.06M
}
515
516
static bool
517
UsesExternalProtocolHandler(const char* aScheme)
518
1.93M
{
519
1.93M
    if (NS_LITERAL_CSTRING("file").Equals(aScheme) ||
520
1.93M
        NS_LITERAL_CSTRING("chrome").Equals(aScheme) ||
521
1.93M
        NS_LITERAL_CSTRING("resource").Equals(aScheme)) {
522
9
        // Don't allow file:, chrome: or resource: URIs to be handled with
523
9
        // nsExternalProtocolHandler, since internally we rely on being able to
524
9
        // use and read from these URIs.
525
9
        return false;
526
9
    }
527
1.93M
528
7.73M
    for (const auto & forcedExternalScheme : gForcedExternalSchemes) {
529
7.73M
      if (!nsCRT::strcasecmp(forcedExternalScheme, aScheme)) {
530
0
        return true;
531
0
      }
532
7.73M
    }
533
1.93M
534
1.93M
    nsAutoCString pref("network.protocol-handler.external.");
535
1.93M
    pref += aScheme;
536
1.93M
537
1.93M
    return Preferences::GetBool(pref.get(), false);
538
1.93M
}
539
540
NS_IMETHODIMP
541
nsIOService::GetProtocolHandler(const char* scheme, nsIProtocolHandler* *result)
542
3.06M
{
543
3.06M
    nsresult rv;
544
3.06M
545
3.06M
    NS_ENSURE_ARG_POINTER(scheme);
546
3.06M
    // XXX we may want to speed this up by introducing our own protocol
547
3.06M
    // scheme -> protocol handler mapping, avoiding the string manipulation
548
3.06M
    // and service manager stuff
549
3.06M
550
3.06M
    rv = GetCachedProtocolHandler(scheme, result);
551
3.06M
    if (NS_SUCCEEDED(rv))
552
3.06M
        return rv;
553
1.93M
554
1.93M
    if (scheme[0] != '\0' && !UsesExternalProtocolHandler(scheme)) {
555
1.93M
        nsAutoCString contractID(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX);
556
1.93M
        contractID += scheme;
557
1.93M
        ToLowerCase(contractID);
558
1.93M
559
1.93M
        rv = CallGetService(contractID.get(), result);
560
1.93M
        if (NS_SUCCEEDED(rv)) {
561
1.64M
            CacheProtocolHandler(scheme, *result);
562
1.64M
            return rv;
563
1.64M
        }
564
285k
565
285k
#ifdef MOZ_WIDGET_GTK
566
285k
        // check to see whether GVFS can handle this URI scheme.  if it can
567
285k
        // create a nsIURI for the "scheme:", then we assume it has support for
568
285k
        // the requested protocol.  otherwise, we failover to using the default
569
285k
        // protocol handler.
570
285k
571
285k
        rv = CallGetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX"moz-gio",
572
285k
                            result);
573
285k
        if (NS_SUCCEEDED(rv)) {
574
285k
            nsAutoCString spec(scheme);
575
285k
            spec.Append(':');
576
285k
577
285k
            nsIURI *uri;
578
285k
            rv = (*result)->NewURI(spec, nullptr, nullptr, &uri);
579
285k
            if (NS_SUCCEEDED(rv)) {
580
0
                NS_RELEASE(uri);
581
0
                return rv;
582
0
            }
583
285k
584
285k
            NS_RELEASE(*result);
585
285k
        }
586
285k
#endif
587
285k
    }
588
1.93M
589
1.93M
    // Okay we don't have a protocol handler to handle this url type, so use
590
1.93M
    // the default protocol handler.  This will cause urls to get dispatched
591
1.93M
    // out to the OS ('cause we can't do anything with them) when we try to
592
1.93M
    // read from a channel created by the default protocol handler.
593
1.93M
594
1.93M
    rv = CallGetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX"default",
595
285k
                        result);
596
285k
    if (NS_FAILED(rv))
597
285k
        return NS_ERROR_UNKNOWN_PROTOCOL;
598
285k
599
285k
    return rv;
600
285k
}
601
602
NS_IMETHODIMP
603
nsIOService::ExtractScheme(const nsACString &inURI, nsACString &scheme)
604
3.05M
{
605
3.05M
    return net_ExtractURLScheme(inURI, scheme);
606
3.05M
}
607
608
NS_IMETHODIMP
609
nsIOService::HostnameIsLocalIPAddress(nsIURI *aURI, bool *aResult)
610
0
{
611
0
  NS_ENSURE_ARG_POINTER(aURI);
612
0
613
0
  nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(aURI);
614
0
  NS_ENSURE_ARG_POINTER(innerURI);
615
0
616
0
  nsAutoCString host;
617
0
  nsresult rv = innerURI->GetAsciiHost(host);
618
0
  if (NS_FAILED(rv)) {
619
0
    return rv;
620
0
  }
621
0
622
0
  *aResult = false;
623
0
624
0
  PRNetAddr addr;
625
0
  PRStatus result = PR_StringToNetAddr(host.get(), &addr);
626
0
  if (result == PR_SUCCESS) {
627
0
    NetAddr netAddr;
628
0
    PRNetAddrToNetAddr(&addr, &netAddr);
629
0
    if (IsIPAddrLocal(&netAddr)) {
630
0
      *aResult = true;
631
0
    }
632
0
  }
633
0
634
0
  return NS_OK;
635
0
}
636
637
NS_IMETHODIMP
638
nsIOService::GetProtocolFlags(const char* scheme, uint32_t *flags)
639
0
{
640
0
    nsCOMPtr<nsIProtocolHandler> handler;
641
0
    nsresult rv = GetProtocolHandler(scheme, getter_AddRefs(handler));
642
0
    if (NS_FAILED(rv)) return rv;
643
0
644
0
    // We can't call DoGetProtocolFlags here because we don't have a URI. This
645
0
    // API is used by (and only used by) extensions, which is why it's still
646
0
    // around. Calling this on a scheme with dynamic flags will throw.
647
0
    rv = handler->GetProtocolFlags(flags);
648
0
#if !IS_ORIGIN_IS_FULL_SPEC_DEFINED
649
0
    MOZ_RELEASE_ASSERT(!(*flags & nsIProtocolHandler::ORIGIN_IS_FULL_SPEC),
650
0
                       "ORIGIN_IS_FULL_SPEC is unsupported but used");
651
0
#endif
652
0
    return rv;
653
0
}
654
655
class AutoIncrement
656
{
657
    public:
658
        explicit AutoIncrement(uint32_t *var) : mVar(var)
659
3.05M
        {
660
3.05M
            ++*var;
661
3.05M
        }
662
        ~AutoIncrement()
663
3.05M
        {
664
3.05M
            --*mVar;
665
3.05M
        }
666
    private:
667
        uint32_t *mVar;
668
};
669
670
nsresult
671
nsIOService::NewURI(const nsACString &aSpec, const char *aCharset, nsIURI *aBaseURI, nsIURI **result)
672
3.05M
{
673
3.05M
    NS_ASSERTION(NS_IsMainThread(), "wrong thread");
674
3.05M
675
3.05M
    static uint32_t recursionCount = 0;
676
3.05M
    if (recursionCount >= MAX_RECURSION_COUNT)
677
3.05M
        return NS_ERROR_MALFORMED_URI;
678
3.05M
    AutoIncrement inc(&recursionCount);
679
3.05M
680
3.05M
    nsAutoCString scheme;
681
3.05M
    nsresult rv = ExtractScheme(aSpec, scheme);
682
3.05M
    if (NS_FAILED(rv)) {
683
1.06M
        // then aSpec is relative
684
1.06M
        if (!aBaseURI)
685
0
            return NS_ERROR_MALFORMED_URI;
686
1.06M
687
1.06M
        if (!aSpec.IsEmpty() && aSpec[0] == '#') {
688
2.32k
            // Looks like a reference instead of a fully-specified URI.
689
2.32k
            // --> initialize |uri| as a clone of |aBaseURI|, with ref appended.
690
2.32k
            return NS_GetURIWithNewRef(aBaseURI, aSpec, result);
691
2.32k
        }
692
1.05M
693
1.05M
        rv = aBaseURI->GetScheme(scheme);
694
1.05M
        if (NS_FAILED(rv)) return rv;
695
3.05M
    }
696
3.05M
697
3.05M
    // now get the handler for this scheme
698
3.05M
    nsCOMPtr<nsIProtocolHandler> handler;
699
3.05M
    rv = GetProtocolHandler(scheme.get(), getter_AddRefs(handler));
700
3.05M
    if (NS_FAILED(rv)) return rv;
701
3.05M
702
3.05M
    return handler->NewURI(aSpec, aCharset, aBaseURI, result);
703
3.05M
}
704
705
706
NS_IMETHODIMP
707
nsIOService::NewFileURI(nsIFile *file, nsIURI **result)
708
0
{
709
0
    nsresult rv;
710
0
    NS_ENSURE_ARG_POINTER(file);
711
0
712
0
    nsCOMPtr<nsIProtocolHandler> handler;
713
0
714
0
    rv = GetProtocolHandler("file", getter_AddRefs(handler));
715
0
    if (NS_FAILED(rv)) return rv;
716
0
717
0
    nsCOMPtr<nsIFileProtocolHandler> fileHandler( do_QueryInterface(handler, &rv) );
718
0
    if (NS_FAILED(rv)) return rv;
719
0
720
0
    return fileHandler->NewFileURI(file, result);
721
0
}
722
723
NS_IMETHODIMP
724
nsIOService::NewChannelFromURI2(nsIURI* aURI,
725
                                nsINode* aLoadingNode,
726
                                nsIPrincipal* aLoadingPrincipal,
727
                                nsIPrincipal* aTriggeringPrincipal,
728
                                uint32_t aSecurityFlags,
729
                                uint32_t aContentPolicyType,
730
                                nsIChannel** result)
731
0
{
732
0
    return NewChannelFromURIWithProxyFlags2(aURI,
733
0
                                            nullptr, // aProxyURI
734
0
                                            0,       // aProxyFlags
735
0
                                            aLoadingNode,
736
0
                                            aLoadingPrincipal,
737
0
                                            aTriggeringPrincipal,
738
0
                                            aSecurityFlags,
739
0
                                            aContentPolicyType,
740
0
                                            result);
741
0
}
742
nsresult
743
nsIOService::NewChannelFromURIWithClientAndController(nsIURI* aURI,
744
                                                      nsINode* aLoadingNode,
745
                                                      nsIPrincipal* aLoadingPrincipal,
746
                                                      nsIPrincipal* aTriggeringPrincipal,
747
                                                      const Maybe<ClientInfo>& aLoadingClientInfo,
748
                                                      const Maybe<ServiceWorkerDescriptor>& aController,
749
                                                      uint32_t aSecurityFlags,
750
                                                      uint32_t aContentPolicyType,
751
                                                      nsIChannel** aResult)
752
5
{
753
5
    return NewChannelFromURIWithProxyFlagsInternal(aURI,
754
5
                                                   nullptr, // aProxyURI
755
5
                                                   0,       // aProxyFlags
756
5
                                                   aLoadingNode,
757
5
                                                   aLoadingPrincipal,
758
5
                                                   aTriggeringPrincipal,
759
5
                                                   aLoadingClientInfo,
760
5
                                                   aController,
761
5
                                                   aSecurityFlags,
762
5
                                                   aContentPolicyType,
763
5
                                                   aResult);
764
5
}
765
766
NS_IMETHODIMP
767
nsIOService::NewChannelFromURIWithLoadInfo(nsIURI* aURI,
768
                                           nsILoadInfo* aLoadInfo,
769
                                           nsIChannel** result)
770
4
{
771
4
  return NewChannelFromURIWithProxyFlagsInternal(aURI,
772
4
                                                 nullptr, // aProxyURI
773
4
                                                 0,       // aProxyFlags
774
4
                                                 aLoadInfo,
775
4
                                                 result);
776
4
}
777
778
779
nsresult
780
nsIOService::NewChannelFromURIWithProxyFlagsInternal(nsIURI* aURI,
781
                                                     nsIURI* aProxyURI,
782
                                                     uint32_t aProxyFlags,
783
                                                     nsINode* aLoadingNode,
784
                                                     nsIPrincipal* aLoadingPrincipal,
785
                                                     nsIPrincipal* aTriggeringPrincipal,
786
                                                     const Maybe<ClientInfo>& aLoadingClientInfo,
787
                                                     const Maybe<ServiceWorkerDescriptor>& aController,
788
                                                     uint32_t aSecurityFlags,
789
                                                     uint32_t aContentPolicyType,
790
                                                     nsIChannel** result)
791
5
{
792
5
    // Ideally all callers of NewChannelFromURIWithProxyFlagsInternal provide
793
5
    // the necessary arguments to create a loadinfo.
794
5
    //
795
5
    // Note, historically this could be called with nullptr aLoadingNode,
796
5
    // aLoadingPrincipal, and aTriggeringPrincipal from addons using
797
5
    // newChannelFromURIWithProxyFlags().  This code tried to accomodate
798
5
    // by not creating a LoadInfo in such cases.  Now that both the legacy
799
5
    // addons and that API are gone we could possibly require always creating a
800
5
    // LoadInfo here.  See bug 1432205.
801
5
    nsCOMPtr<nsILoadInfo> loadInfo;
802
5
803
5
    // TYPE_DOCUMENT loads don't require a loadingNode or principal, but other
804
5
    // types do.
805
5
    if (aLoadingNode || aLoadingPrincipal ||
806
5
        aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT) {
807
5
      loadInfo = new LoadInfo(aLoadingPrincipal,
808
5
                              aTriggeringPrincipal,
809
5
                              aLoadingNode,
810
5
                              aSecurityFlags,
811
5
                              aContentPolicyType,
812
5
                              aLoadingClientInfo,
813
5
                              aController);
814
5
    }
815
5
    NS_ASSERTION(loadInfo, "Please pass security info when creating a channel");
816
5
    return NewChannelFromURIWithProxyFlagsInternal(aURI,
817
5
                                                   aProxyURI,
818
5
                                                   aProxyFlags,
819
5
                                                   loadInfo,
820
5
                                                   result);
821
5
}
822
823
nsresult
824
nsIOService::NewChannelFromURIWithProxyFlagsInternal(nsIURI* aURI,
825
                                                     nsIURI* aProxyURI,
826
                                                     uint32_t aProxyFlags,
827
                                                     nsILoadInfo* aLoadInfo,
828
                                                     nsIChannel** result)
829
9
{
830
9
    nsresult rv;
831
9
    NS_ENSURE_ARG_POINTER(aURI);
832
9
833
9
    nsAutoCString scheme;
834
9
    rv = aURI->GetScheme(scheme);
835
9
    if (NS_FAILED(rv))
836
9
        return rv;
837
9
838
9
    nsCOMPtr<nsIProtocolHandler> handler;
839
9
    rv = GetProtocolHandler(scheme.get(), getter_AddRefs(handler));
840
9
    if (NS_FAILED(rv))
841
9
        return rv;
842
9
843
9
    uint32_t protoFlags;
844
9
    rv = handler->DoGetProtocolFlags(aURI, &protoFlags);
845
9
    if (NS_FAILED(rv))
846
9
        return rv;
847
9
848
9
    // Ideally we are creating new channels by calling NewChannel2 (NewProxiedChannel2).
849
9
    // Keep in mind that Addons can implement their own Protocolhandlers, hence
850
9
    // NewChannel2() might *not* be implemented.
851
9
    // We do not want to break those addons, therefore we first try to create a channel
852
9
    // calling NewChannel2(); if that fails:
853
9
    // * we fall back to creating a channel by calling NewChannel()
854
9
    // * wrap the addon channel
855
9
    // * and attach the loadInfo to the channel wrapper
856
9
    nsCOMPtr<nsIChannel> channel;
857
9
    nsCOMPtr<nsIProxiedProtocolHandler> pph = do_QueryInterface(handler);
858
9
    if (pph) {
859
0
        rv = pph->NewProxiedChannel2(aURI, nullptr, aProxyFlags, aProxyURI,
860
0
                                     aLoadInfo, getter_AddRefs(channel));
861
0
        // if calling NewProxiedChannel2() fails we try to fall back to
862
0
        // creating a new proxied channel by calling NewProxiedChannel().
863
0
        if (NS_FAILED(rv)) {
864
0
            rv = pph->NewProxiedChannel(aURI, nullptr, aProxyFlags, aProxyURI,
865
0
                                        getter_AddRefs(channel));
866
0
            NS_ENSURE_SUCCESS(rv, rv);
867
0
868
0
            // The protocol handler does not implement NewProxiedChannel2, so
869
0
            // maybe we need to wrap the channel (see comment in MaybeWrap
870
0
            // function).
871
0
            channel = nsSecCheckWrapChannel::MaybeWrap(channel, aLoadInfo);
872
0
        }
873
0
    }
874
9
    else {
875
9
        rv = handler->NewChannel2(aURI, aLoadInfo, getter_AddRefs(channel));
876
9
        // if an implementation of NewChannel2() is missing we try to fall back to
877
9
        // creating a new channel by calling NewChannel().
878
9
        if (rv == NS_ERROR_NOT_IMPLEMENTED ||
879
9
            rv == NS_ERROR_XPC_JSOBJECT_HAS_NO_FUNCTION_NAMED) {
880
0
            LOG(("NewChannel2 not implemented rv=%" PRIx32
881
0
                 ". Falling back to NewChannel\n", static_cast<uint32_t>(rv)));
882
0
            rv = handler->NewChannel(aURI, getter_AddRefs(channel));
883
0
            if (NS_FAILED(rv)) {
884
0
                return rv;
885
0
            }
886
0
            // The protocol handler does not implement NewChannel2, so
887
0
            // maybe we need to wrap the channel (see comment in MaybeWrap
888
0
            // function).
889
0
            channel = nsSecCheckWrapChannel::MaybeWrap(channel, aLoadInfo);
890
9
        } else if (NS_FAILED(rv)) {
891
0
            return rv;
892
0
        }
893
9
    }
894
9
895
9
    // Make sure that all the individual protocolhandlers attach a loadInfo.
896
9
    if (aLoadInfo) {
897
9
      // make sure we have the same instance of loadInfo on the newly created channel
898
9
      nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
899
9
      if (aLoadInfo != loadInfo) {
900
0
        MOZ_ASSERT(false, "newly created channel must have a loadinfo attached");
901
0
        return NS_ERROR_UNEXPECTED;
902
0
      }
903
9
904
9
      // If we're sandboxed, make sure to clear any owner the channel
905
9
      // might already have.
906
9
      if (loadInfo->GetLoadingSandboxed()) {
907
0
        channel->SetOwner(nullptr);
908
0
      }
909
9
    }
910
9
911
9
    // Some extensions override the http protocol handler and provide their own
912
9
    // implementation. The channels returned from that implementation doesn't
913
9
    // seem to always implement the nsIUploadChannel2 interface, presumably
914
9
    // because it's a new interface.
915
9
    // Eventually we should remove this and simply require that http channels
916
9
    // implement the new interface.
917
9
    // See bug 529041
918
9
    if (!gHasWarnedUploadChannel2 && scheme.EqualsLiteral("http")) {
919
0
        nsCOMPtr<nsIUploadChannel2> uploadChannel2 = do_QueryInterface(channel);
920
0
        if (!uploadChannel2) {
921
0
            nsCOMPtr<nsIConsoleService> consoleService =
922
0
                do_GetService(NS_CONSOLESERVICE_CONTRACTID);
923
0
            if (consoleService) {
924
0
                consoleService->LogStringMessage(u"Http channel implementation "
925
0
                    "doesn't support nsIUploadChannel2. An extension has "
926
0
                    "supplied a non-functional http protocol handler. This will "
927
0
                    "break behavior and in future releases not work at all.");
928
0
            }
929
0
            gHasWarnedUploadChannel2 = true;
930
0
        }
931
0
    }
932
9
933
9
    channel.forget(result);
934
9
    return NS_OK;
935
9
}
936
937
NS_IMETHODIMP
938
nsIOService::NewChannelFromURIWithProxyFlags2(nsIURI* aURI,
939
                                              nsIURI* aProxyURI,
940
                                              uint32_t aProxyFlags,
941
                                              nsINode* aLoadingNode,
942
                                              nsIPrincipal* aLoadingPrincipal,
943
                                              nsIPrincipal* aTriggeringPrincipal,
944
                                              uint32_t aSecurityFlags,
945
                                              uint32_t aContentPolicyType,
946
                                              nsIChannel** result)
947
0
{
948
0
    return NewChannelFromURIWithProxyFlagsInternal(aURI,
949
0
                                                   aProxyURI,
950
0
                                                   aProxyFlags,
951
0
                                                   aLoadingNode,
952
0
                                                   aLoadingPrincipal,
953
0
                                                   aTriggeringPrincipal,
954
0
                                                   Maybe<ClientInfo>(),
955
0
                                                   Maybe<ServiceWorkerDescriptor>(),
956
0
                                                   aSecurityFlags,
957
0
                                                   aContentPolicyType,
958
0
                                                   result);
959
0
}
960
961
NS_IMETHODIMP
962
nsIOService::NewChannel2(const nsACString& aSpec,
963
                         const char* aCharset,
964
                         nsIURI* aBaseURI,
965
                         nsINode* aLoadingNode,
966
                         nsIPrincipal* aLoadingPrincipal,
967
                         nsIPrincipal* aTriggeringPrincipal,
968
                         uint32_t aSecurityFlags,
969
                         uint32_t aContentPolicyType,
970
                         nsIChannel** result)
971
0
{
972
0
    nsresult rv;
973
0
    nsCOMPtr<nsIURI> uri;
974
0
    rv = NewURI(aSpec, aCharset, aBaseURI, getter_AddRefs(uri));
975
0
    if (NS_FAILED(rv)) return rv;
976
0
977
0
    return NewChannelFromURI2(uri,
978
0
                              aLoadingNode,
979
0
                              aLoadingPrincipal,
980
0
                              aTriggeringPrincipal,
981
0
                              aSecurityFlags,
982
0
                              aContentPolicyType,
983
0
                              result);
984
0
}
985
986
bool
987
nsIOService::IsLinkUp()
988
0
{
989
0
    InitializeNetworkLinkService();
990
0
991
0
    if (!mNetworkLinkService) {
992
0
        // We cannot decide, assume the link is up
993
0
        return true;
994
0
    }
995
0
996
0
    bool isLinkUp;
997
0
    nsresult rv;
998
0
    rv = mNetworkLinkService->GetIsLinkUp(&isLinkUp);
999
0
    if (NS_FAILED(rv)) {
1000
0
        return true;
1001
0
    }
1002
0
1003
0
    return isLinkUp;
1004
0
}
1005
1006
NS_IMETHODIMP
1007
nsIOService::GetOffline(bool *offline)
1008
0
{
1009
0
    if (mOfflineMirrorsConnectivity) {
1010
0
        *offline = mOffline || !mConnectivity;
1011
0
    } else {
1012
0
        *offline = mOffline;
1013
0
    }
1014
0
    return NS_OK;
1015
0
}
1016
1017
NS_IMETHODIMP
1018
nsIOService::SetOffline(bool offline)
1019
3
{
1020
3
    LOG(("nsIOService::SetOffline offline=%d\n", offline));
1021
3
    // When someone wants to go online (!offline) after we got XPCOM shutdown
1022
3
    // throw ERROR_NOT_AVAILABLE to prevent return to online state.
1023
3
    if ((mShutdown || mOfflineForProfileChange) && !offline)
1024
0
        return NS_ERROR_NOT_AVAILABLE;
1025
3
1026
3
    // SetOffline() may re-enter while it's shutting down services.
1027
3
    // If that happens, save the most recent value and it will be
1028
3
    // processed when the first SetOffline() call is done bringing
1029
3
    // down the service.
1030
3
    mSetOfflineValue = offline;
1031
3
    if (mSettingOffline) {
1032
0
        return NS_OK;
1033
0
    }
1034
3
1035
3
    mSettingOffline = true;
1036
3
1037
3
    nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
1038
3
1039
3
    NS_ASSERTION(observerService, "The observer service should not be null");
1040
3
1041
3
    if (XRE_IsParentProcess()) {
1042
3
        if (observerService) {
1043
3
            (void)observerService->NotifyObservers(nullptr,
1044
3
                NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC, offline ?
1045
0
                u"true" :
1046
3
                u"false");
1047
3
        }
1048
3
    }
1049
3
1050
3
    nsIIOService *subject = static_cast<nsIIOService *>(this);
1051
6
    while (mSetOfflineValue != mOffline) {
1052
3
        offline = mSetOfflineValue;
1053
3
1054
3
        if (offline && !mOffline) {
1055
0
            mOffline = true; // indicate we're trying to shutdown
1056
0
1057
0
            // don't care if notifications fail
1058
0
            if (observerService)
1059
0
                observerService->NotifyObservers(subject,
1060
0
                                                 NS_IOSERVICE_GOING_OFFLINE_TOPIC,
1061
0
                                                 u"" NS_IOSERVICE_OFFLINE);
1062
0
1063
0
            if (mSocketTransportService)
1064
0
                mSocketTransportService->SetOffline(true);
1065
0
1066
0
            mLastOfflineStateChange = PR_IntervalNow();
1067
0
            if (observerService)
1068
0
                observerService->NotifyObservers(subject,
1069
0
                                                 NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
1070
0
                                                 u"" NS_IOSERVICE_OFFLINE);
1071
0
        }
1072
3
        else if (!offline && mOffline) {
1073
3
            // go online
1074
3
            InitializeSocketTransportService();
1075
3
            mOffline = false;    // indicate success only AFTER we've
1076
3
                                    // brought up the services
1077
3
1078
3
            mLastOfflineStateChange = PR_IntervalNow();
1079
3
            // don't care if notification fails
1080
3
            // Only send the ONLINE notification if there is connectivity
1081
3
            if (observerService && mConnectivity) {
1082
3
                observerService->NotifyObservers(subject,
1083
3
                                                 NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
1084
3
                                                 (u"" NS_IOSERVICE_ONLINE));
1085
3
            }
1086
3
        }
1087
3
    }
1088
3
1089
3
    // Don't notify here, as the above notifications (if used) suffice.
1090
3
    if ((mShutdown || mOfflineForProfileChange) && mOffline) {
1091
0
        if (mSocketTransportService) {
1092
0
            DebugOnly<nsresult> rv = mSocketTransportService->Shutdown(mShutdown);
1093
0
            NS_ASSERTION(NS_SUCCEEDED(rv), "socket transport service shutdown failed");
1094
0
        }
1095
0
    }
1096
3
1097
3
    mSettingOffline = false;
1098
3
1099
3
    return NS_OK;
1100
3
}
1101
1102
NS_IMETHODIMP
1103
nsIOService::GetConnectivity(bool *aConnectivity)
1104
0
{
1105
0
    *aConnectivity = mConnectivity;
1106
0
    return NS_OK;
1107
0
}
1108
1109
NS_IMETHODIMP
1110
nsIOService::SetConnectivity(bool aConnectivity)
1111
0
{
1112
0
    LOG(("nsIOService::SetConnectivity aConnectivity=%d\n", aConnectivity));
1113
0
    // This should only be called from ContentChild to pass the connectivity
1114
0
    // value from the chrome process to the content process.
1115
0
    if (XRE_IsParentProcess()) {
1116
0
        return NS_ERROR_NOT_AVAILABLE;
1117
0
    }
1118
0
    return SetConnectivityInternal(aConnectivity);
1119
0
}
1120
1121
nsresult
1122
nsIOService::SetConnectivityInternal(bool aConnectivity)
1123
0
{
1124
0
    LOG(("nsIOService::SetConnectivityInternal aConnectivity=%d\n", aConnectivity));
1125
0
    if (mConnectivity == aConnectivity) {
1126
0
        // Nothing to do here.
1127
0
        return NS_OK;
1128
0
    }
1129
0
    mConnectivity = aConnectivity;
1130
0
1131
0
    // This is used for PR_Connect PR_Close telemetry so it is important that
1132
0
    // we have statistic about network change event even if we are offline.
1133
0
    mLastConnectivityChange = PR_IntervalNow();
1134
0
1135
0
    if (mCaptivePortalService) {
1136
0
        if (aConnectivity && gCaptivePortalEnabled) {
1137
0
            // This will also trigger a captive portal check for the new network
1138
0
            static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Start();
1139
0
        } else {
1140
0
            static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Stop();
1141
0
        }
1142
0
    }
1143
0
1144
0
    nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
1145
0
    if (!observerService) {
1146
0
        return NS_OK;
1147
0
    }
1148
0
    // This notification sends the connectivity to the child processes
1149
0
    if (XRE_IsParentProcess()) {
1150
0
        observerService->NotifyObservers(nullptr,
1151
0
            NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC, aConnectivity ?
1152
0
            u"true" :
1153
0
            u"false");
1154
0
    }
1155
0
1156
0
    if (mOffline) {
1157
0
      // We don't need to send any notifications if we're offline
1158
0
      return NS_OK;
1159
0
    }
1160
0
1161
0
    if (aConnectivity) {
1162
0
        // If we were previously offline due to connectivity=false,
1163
0
        // send the ONLINE notification
1164
0
        observerService->NotifyObservers(
1165
0
            static_cast<nsIIOService *>(this),
1166
0
            NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
1167
0
            (u"" NS_IOSERVICE_ONLINE));
1168
0
    } else {
1169
0
        // If we were previously online and lost connectivity
1170
0
        // send the OFFLINE notification
1171
0
        observerService->NotifyObservers(static_cast<nsIIOService *>(this),
1172
0
                                         NS_IOSERVICE_GOING_OFFLINE_TOPIC,
1173
0
                                         u"" NS_IOSERVICE_OFFLINE);
1174
0
        observerService->NotifyObservers(static_cast<nsIIOService *>(this),
1175
0
                                         NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
1176
0
                                         u"" NS_IOSERVICE_OFFLINE);
1177
0
    }
1178
0
    return NS_OK;
1179
0
}
1180
1181
NS_IMETHODIMP
1182
nsIOService::AllowPort(int32_t inPort, const char *scheme, bool *_retval)
1183
0
{
1184
0
    int16_t port = inPort;
1185
0
    if (port == -1) {
1186
0
        *_retval = true;
1187
0
        return NS_OK;
1188
0
    }
1189
0
1190
0
    if (port == 0) {
1191
0
        *_retval = false;
1192
0
        return NS_OK;
1193
0
    }
1194
0
1195
0
    // first check to see if the port is in our blacklist:
1196
0
    int32_t badPortListCnt = mRestrictedPortList.Length();
1197
0
    for (int i=0; i<badPortListCnt; i++)
1198
0
    {
1199
0
        if (port == mRestrictedPortList[i])
1200
0
        {
1201
0
            *_retval = false;
1202
0
1203
0
            // check to see if the protocol wants to override
1204
0
            if (!scheme)
1205
0
                return NS_OK;
1206
0
1207
0
            nsCOMPtr<nsIProtocolHandler> handler;
1208
0
            nsresult rv = GetProtocolHandler(scheme, getter_AddRefs(handler));
1209
0
            if (NS_FAILED(rv)) return rv;
1210
0
1211
0
            // let the protocol handler decide
1212
0
            return handler->AllowPort(port, scheme, _retval);
1213
0
        }
1214
0
    }
1215
0
1216
0
    *_retval = true;
1217
0
    return NS_OK;
1218
0
}
1219
1220
////////////////////////////////////////////////////////////////////////////////
1221
1222
void
1223
nsIOService::PrefsChanged(const char *pref)
1224
3
{
1225
3
    // Look for extra ports to block
1226
3
    if (!pref || strcmp(pref, PORT_PREF("banned")) == 0)
1227
3
        ParsePortList(PORT_PREF("banned"), false);
1228
3
1229
3
    // ...as well as previous blocks to remove.
1230
3
    if (!pref || strcmp(pref, PORT_PREF("banned.override")) == 0)
1231
3
        ParsePortList(PORT_PREF("banned.override"), true);
1232
3
1233
3
    if (!pref || strcmp(pref, MANAGE_OFFLINE_STATUS_PREF) == 0) {
1234
3
        bool manage;
1235
3
        if (mNetworkLinkServiceInitialized &&
1236
3
            NS_SUCCEEDED(Preferences::GetBool(MANAGE_OFFLINE_STATUS_PREF,
1237
3
                                              &manage))) {
1238
0
            LOG(("nsIOService::PrefsChanged ManageOfflineStatus manage=%d\n", manage));
1239
0
            SetManageOfflineStatus(manage);
1240
0
        }
1241
3
    }
1242
3
1243
3
    if (!pref || strcmp(pref, NECKO_BUFFER_CACHE_COUNT_PREF) == 0) {
1244
3
        int32_t count;
1245
3
        if (NS_SUCCEEDED(Preferences::GetInt(NECKO_BUFFER_CACHE_COUNT_PREF,
1246
3
                                             &count)))
1247
3
            /* check for bogus values and default if we find such a value */
1248
3
            if (count > 0)
1249
3
                gDefaultSegmentCount = count;
1250
3
    }
1251
3
1252
3
    if (!pref || strcmp(pref, NECKO_BUFFER_CACHE_SIZE_PREF) == 0) {
1253
3
        int32_t size;
1254
3
        if (NS_SUCCEEDED(Preferences::GetInt(NECKO_BUFFER_CACHE_SIZE_PREF,
1255
3
                                             &size)))
1256
3
            /* check for bogus values and default if we find such a value
1257
3
             * the upper limit here is arbitrary. having a 1mb segment size
1258
3
             * is pretty crazy.  if you remove this, consider adding some
1259
3
             * integer rollover test.
1260
3
             */
1261
3
            if (size > 0 && size < 1024*1024)
1262
3
                gDefaultSegmentSize = size;
1263
3
        NS_WARNING_ASSERTION(!(size & (size - 1)),
1264
3
                             "network segment size is not a power of 2!");
1265
3
    }
1266
3
1267
3
    if (!pref || strcmp(pref, NETWORK_NOTIFY_CHANGED_PREF) == 0) {
1268
3
        bool allow;
1269
3
        nsresult rv = Preferences::GetBool(NETWORK_NOTIFY_CHANGED_PREF, &allow);
1270
3
        if (NS_SUCCEEDED(rv)) {
1271
3
            mNetworkNotifyChanged = allow;
1272
3
        }
1273
3
    }
1274
3
1275
3
    if (!pref || strcmp(pref, NETWORK_CAPTIVE_PORTAL_PREF) == 0) {
1276
3
        nsresult rv = Preferences::GetBool(NETWORK_CAPTIVE_PORTAL_PREF, &gCaptivePortalEnabled);
1277
3
        if (NS_SUCCEEDED(rv) && mCaptivePortalService) {
1278
3
            if (gCaptivePortalEnabled) {
1279
0
                static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Start();
1280
3
            } else {
1281
3
                static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Stop();
1282
3
            }
1283
3
        }
1284
3
    }
1285
3
}
1286
1287
void
1288
nsIOService::ParsePortList(const char *pref, bool remove)
1289
6
{
1290
6
    nsAutoCString portList;
1291
6
1292
6
    // Get a pref string and chop it up into a list of ports.
1293
6
    Preferences::GetCString(pref, portList);
1294
6
    if (!portList.IsVoid()) {
1295
0
        nsTArray<nsCString> portListArray;
1296
0
        ParseString(portList, ',', portListArray);
1297
0
        uint32_t index;
1298
0
        for (index=0; index < portListArray.Length(); index++) {
1299
0
            portListArray[index].StripWhitespace();
1300
0
            int32_t portBegin, portEnd;
1301
0
1302
0
            if (PR_sscanf(portListArray[index].get(), "%d-%d", &portBegin, &portEnd) == 2) {
1303
0
               if ((portBegin < 65536) && (portEnd < 65536)) {
1304
0
                   int32_t curPort;
1305
0
                   if (remove) {
1306
0
                        for (curPort=portBegin; curPort <= portEnd; curPort++)
1307
0
                            mRestrictedPortList.RemoveElement(curPort);
1308
0
                   } else {
1309
0
                        for (curPort=portBegin; curPort <= portEnd; curPort++)
1310
0
                            mRestrictedPortList.AppendElement(curPort);
1311
0
                   }
1312
0
               }
1313
0
            } else {
1314
0
               nsresult aErrorCode;
1315
0
               int32_t port = portListArray[index].ToInteger(&aErrorCode);
1316
0
               if (NS_SUCCEEDED(aErrorCode) && port < 65536) {
1317
0
                   if (remove)
1318
0
                       mRestrictedPortList.RemoveElement(port);
1319
0
                   else
1320
0
                       mRestrictedPortList.AppendElement(port);
1321
0
               }
1322
0
            }
1323
0
1324
0
        }
1325
0
    }
1326
6
}
1327
1328
class nsWakeupNotifier : public Runnable
1329
{
1330
public:
1331
  explicit nsWakeupNotifier(nsIIOServiceInternal* ioService)
1332
    : Runnable("net::nsWakeupNotifier")
1333
    , mIOService(ioService)
1334
0
  {
1335
0
  }
1336
1337
0
  NS_IMETHOD Run() override { return mIOService->NotifyWakeup(); }
1338
1339
private:
1340
0
    virtual ~nsWakeupNotifier() = default;
1341
    nsCOMPtr<nsIIOServiceInternal> mIOService;
1342
};
1343
1344
NS_IMETHODIMP
1345
nsIOService::NotifyWakeup()
1346
0
{
1347
0
    nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
1348
0
1349
0
    NS_ASSERTION(observerService, "The observer service should not be null");
1350
0
1351
0
    if (observerService && mNetworkNotifyChanged) {
1352
0
        (void)observerService->
1353
0
            NotifyObservers(nullptr,
1354
0
                            NS_NETWORK_LINK_TOPIC,
1355
0
                            (u"" NS_NETWORK_LINK_DATA_CHANGED));
1356
0
    }
1357
0
1358
0
    RecheckCaptivePortal();
1359
0
1360
0
    return NS_OK;
1361
0
}
1362
1363
void
1364
nsIOService::SetHttpHandlerAlreadyShutingDown()
1365
0
{
1366
0
    if (!mShutdown && !mOfflineForProfileChange) {
1367
0
        mNetTearingDownStarted = PR_IntervalNow();
1368
0
        mHttpHandlerAlreadyShutingDown = true;
1369
0
    }
1370
0
}
1371
1372
// nsIObserver interface
1373
NS_IMETHODIMP
1374
nsIOService::Observe(nsISupports *subject,
1375
                     const char *topic,
1376
                     const char16_t *data)
1377
0
{
1378
0
    if (!strcmp(topic, kProfileChangeNetTeardownTopic)) {
1379
0
        if (!mHttpHandlerAlreadyShutingDown) {
1380
0
          mNetTearingDownStarted = PR_IntervalNow();
1381
0
        }
1382
0
        mHttpHandlerAlreadyShutingDown = false;
1383
0
        if (!mOffline) {
1384
0
            mOfflineForProfileChange = true;
1385
0
            SetOffline(true);
1386
0
        }
1387
0
    } else if (!strcmp(topic, kProfileChangeNetRestoreTopic)) {
1388
0
        if (mOfflineForProfileChange) {
1389
0
            mOfflineForProfileChange = false;
1390
0
            SetOffline(false);
1391
0
        }
1392
0
    } else if (!strcmp(topic, kProfileDoChange)) {
1393
0
        if (data && NS_LITERAL_STRING("startup").Equals(data)) {
1394
0
            // Lazy initialization of network link service (see bug 620472)
1395
0
            InitializeNetworkLinkService();
1396
0
            // Set up the initilization flag regardless the actuall result.
1397
0
            // If we fail here, we will fail always on.
1398
0
            mNetworkLinkServiceInitialized = true;
1399
0
1400
0
            // And now reflect the preference setting
1401
0
            PrefsChanged(MANAGE_OFFLINE_STATUS_PREF);
1402
0
1403
0
            // Bug 870460 - Read cookie database at an early-as-possible time
1404
0
            // off main thread. Hence, we have more chance to finish db query
1405
0
            // before something calls into the cookie service.
1406
0
            nsCOMPtr<nsISupports> cookieServ = do_GetService(NS_COOKIESERVICE_CONTRACTID);
1407
0
        }
1408
0
    } else if (!strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
1409
0
        // Remember we passed XPCOM shutdown notification to prevent any
1410
0
        // changes of the offline status from now. We must not allow going
1411
0
        // online after this point.
1412
0
        mShutdown = true;
1413
0
1414
0
        if (!mHttpHandlerAlreadyShutingDown && !mOfflineForProfileChange) {
1415
0
          mNetTearingDownStarted = PR_IntervalNow();
1416
0
        }
1417
0
        mHttpHandlerAlreadyShutingDown = false;
1418
0
1419
0
        SetOffline(true);
1420
0
1421
0
        if (mCaptivePortalService) {
1422
0
            static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Stop();
1423
0
            mCaptivePortalService = nullptr;
1424
0
        }
1425
0
1426
0
    } else if (!strcmp(topic, NS_NETWORK_LINK_TOPIC)) {
1427
0
        OnNetworkLinkEvent(NS_ConvertUTF16toUTF8(data).get());
1428
0
    } else if (!strcmp(topic, NS_WIDGET_WAKE_OBSERVER_TOPIC)) {
1429
0
        // coming back alive from sleep
1430
0
        // this indirection brought to you by:
1431
0
        // https://bugzilla.mozilla.org/show_bug.cgi?id=1152048#c19
1432
0
        nsCOMPtr<nsIRunnable> wakeupNotifier = new nsWakeupNotifier(this);
1433
0
        NS_DispatchToMainThread(wakeupNotifier);
1434
0
    }
1435
0
1436
0
    return NS_OK;
1437
0
}
1438
1439
// nsINetUtil interface
1440
NS_IMETHODIMP
1441
nsIOService::ParseRequestContentType(const nsACString &aTypeHeader,
1442
                                     nsACString &aCharset,
1443
                                     bool *aHadCharset,
1444
                                     nsACString &aContentType)
1445
0
{
1446
0
    net_ParseRequestContentType(aTypeHeader, aContentType, aCharset, aHadCharset);
1447
0
    return NS_OK;
1448
0
}
1449
1450
// nsINetUtil interface
1451
NS_IMETHODIMP
1452
nsIOService::ParseResponseContentType(const nsACString &aTypeHeader,
1453
                                      nsACString &aCharset,
1454
                                      bool *aHadCharset,
1455
                                      nsACString &aContentType)
1456
0
{
1457
0
    net_ParseContentType(aTypeHeader, aContentType, aCharset, aHadCharset);
1458
0
    return NS_OK;
1459
0
}
1460
1461
NS_IMETHODIMP
1462
nsIOService::ProtocolHasFlags(nsIURI   *uri,
1463
                              uint32_t  flags,
1464
                              bool     *result)
1465
11.7k
{
1466
11.7k
    NS_ENSURE_ARG(uri);
1467
11.7k
1468
11.7k
    *result = false;
1469
11.7k
    nsAutoCString scheme;
1470
11.7k
    nsresult rv = uri->GetScheme(scheme);
1471
11.7k
    NS_ENSURE_SUCCESS(rv, rv);
1472
11.7k
1473
11.7k
    // Grab the protocol flags from the URI.
1474
11.7k
    uint32_t protocolFlags;
1475
11.7k
    nsCOMPtr<nsIProtocolHandler> handler;
1476
11.7k
    rv = GetProtocolHandler(scheme.get(), getter_AddRefs(handler));
1477
11.7k
    NS_ENSURE_SUCCESS(rv, rv);
1478
11.7k
    rv = handler->DoGetProtocolFlags(uri, &protocolFlags);
1479
11.7k
    NS_ENSURE_SUCCESS(rv, rv);
1480
11.7k
1481
11.7k
    *result = (protocolFlags & flags) == flags;
1482
11.7k
    return NS_OK;
1483
11.7k
}
1484
1485
NS_IMETHODIMP
1486
nsIOService::URIChainHasFlags(nsIURI   *uri,
1487
                              uint32_t  flags,
1488
                              bool     *result)
1489
11.6k
{
1490
11.6k
    nsresult rv = ProtocolHasFlags(uri, flags, result);
1491
11.6k
    NS_ENSURE_SUCCESS(rv, rv);
1492
11.6k
1493
11.6k
    if (*result) {
1494
39
        return rv;
1495
39
    }
1496
11.6k
1497
11.6k
    // Dig deeper into the chain.  Note that this is not a do/while loop to
1498
11.6k
    // avoid the extra addref/release on |uri| in the common (non-nested) case.
1499
11.6k
    nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(uri);
1500
11.6k
    while (nestedURI) {
1501
90
        nsCOMPtr<nsIURI> innerURI;
1502
90
        rv = nestedURI->GetInnerURI(getter_AddRefs(innerURI));
1503
90
        NS_ENSURE_SUCCESS(rv, rv);
1504
90
1505
90
        rv = ProtocolHasFlags(innerURI, flags, result);
1506
90
1507
90
        if (*result) {
1508
90
            return rv;
1509
90
        }
1510
0
1511
0
        nestedURI = do_QueryInterface(innerURI);
1512
0
    }
1513
11.6k
1514
11.6k
    return rv;
1515
11.6k
}
1516
1517
NS_IMETHODIMP
1518
nsIOService::SetManageOfflineStatus(bool aManage)
1519
0
{
1520
0
    LOG(("nsIOService::SetManageOfflineStatus aManage=%d\n", aManage));
1521
0
    mManageLinkStatus = aManage;
1522
0
1523
0
    // When detection is not activated, the default connectivity state is true.
1524
0
    if (!mManageLinkStatus) {
1525
0
        SetConnectivityInternal(true);
1526
0
        return NS_OK;
1527
0
    }
1528
0
1529
0
    InitializeNetworkLinkService();
1530
0
    // If the NetworkLinkService is already initialized, it does not call
1531
0
    // OnNetworkLinkEvent. This is needed, when mManageLinkStatus goes from
1532
0
    // false to true.
1533
0
    OnNetworkLinkEvent(NS_NETWORK_LINK_DATA_UNKNOWN);
1534
0
    return NS_OK;
1535
0
}
1536
1537
NS_IMETHODIMP
1538
nsIOService::GetManageOfflineStatus(bool* aManage)
1539
0
{
1540
0
    *aManage = mManageLinkStatus;
1541
0
    return NS_OK;
1542
0
}
1543
1544
// input argument 'data' is already UTF8'ed
1545
nsresult
1546
nsIOService::OnNetworkLinkEvent(const char *data)
1547
3
{
1548
3
    if (IsNeckoChild()) {
1549
0
        // There is nothing IO service could do on the child process
1550
0
        // with this at the moment.  Feel free to add functionality
1551
0
        // here at will, though.
1552
0
        return NS_OK;
1553
0
    }
1554
3
1555
3
    if (mShutdown) {
1556
0
        return NS_ERROR_NOT_AVAILABLE;
1557
0
    }
1558
3
1559
3
    nsCString dataAsString(data);
1560
3
    for (auto* cp : mozilla::dom::ContentParent::AllProcesses(mozilla::dom::ContentParent::eLive)) {
1561
0
        PNeckoParent* neckoParent = SingleManagedOrNull(cp->ManagedPNeckoParent());
1562
0
        if (!neckoParent) {
1563
0
            continue;
1564
0
        }
1565
0
        Unused << neckoParent->SendNetworkChangeNotification(dataAsString);
1566
0
    }
1567
3
1568
3
    LOG(("nsIOService::OnNetworkLinkEvent data:%s\n", data));
1569
3
    if (!mNetworkLinkService) {
1570
0
        return NS_ERROR_FAILURE;
1571
0
    }
1572
3
1573
3
    if (!mManageLinkStatus) {
1574
3
        LOG(("nsIOService::OnNetworkLinkEvent mManageLinkStatus=false\n"));
1575
3
        return NS_OK;
1576
3
    }
1577
0
1578
0
    bool isUp = true;
1579
0
    if (!strcmp(data, NS_NETWORK_LINK_DATA_CHANGED)) {
1580
0
        mLastNetworkLinkChange = PR_IntervalNow();
1581
0
        // CHANGED means UP/DOWN didn't change
1582
0
        // but the status of the captive portal may have changed.
1583
0
        RecheckCaptivePortal();
1584
0
        return NS_OK;
1585
0
    }
1586
0
    if (!strcmp(data, NS_NETWORK_LINK_DATA_DOWN)) {
1587
0
        isUp = false;
1588
0
    } else if (!strcmp(data, NS_NETWORK_LINK_DATA_UP)) {
1589
0
        isUp = true;
1590
0
    } else if (!strcmp(data, NS_NETWORK_LINK_DATA_UNKNOWN)) {
1591
0
        nsresult rv = mNetworkLinkService->GetIsLinkUp(&isUp);
1592
0
        NS_ENSURE_SUCCESS(rv, rv);
1593
0
    } else {
1594
0
        NS_WARNING("Unhandled network event!");
1595
0
        return NS_OK;
1596
0
    }
1597
0
1598
0
    return SetConnectivityInternal(isUp);
1599
0
}
1600
1601
NS_IMETHODIMP
1602
nsIOService::EscapeString(const nsACString& aString,
1603
                          uint32_t aEscapeType,
1604
                          nsACString& aResult)
1605
0
{
1606
0
  NS_ENSURE_ARG_MAX(aEscapeType, 4);
1607
0
1608
0
  nsAutoCString stringCopy(aString);
1609
0
  nsCString result;
1610
0
1611
0
  if (!NS_Escape(stringCopy, result, (nsEscapeMask) aEscapeType))
1612
0
    return NS_ERROR_OUT_OF_MEMORY;
1613
0
1614
0
  aResult.Assign(result);
1615
0
1616
0
  return NS_OK;
1617
0
}
1618
1619
NS_IMETHODIMP
1620
nsIOService::EscapeURL(const nsACString &aStr,
1621
                       uint32_t aFlags, nsACString &aResult)
1622
0
{
1623
0
  aResult.Truncate();
1624
0
  NS_EscapeURL(aStr.BeginReading(), aStr.Length(),
1625
0
               aFlags | esc_AlwaysCopy, aResult);
1626
0
  return NS_OK;
1627
0
}
1628
1629
NS_IMETHODIMP
1630
nsIOService::UnescapeString(const nsACString &aStr,
1631
                            uint32_t aFlags, nsACString &aResult)
1632
0
{
1633
0
  aResult.Truncate();
1634
0
  NS_UnescapeURL(aStr.BeginReading(), aStr.Length(),
1635
0
                 aFlags | esc_AlwaysCopy, aResult);
1636
0
  return NS_OK;
1637
0
}
1638
1639
NS_IMETHODIMP
1640
nsIOService::ExtractCharsetFromContentType(const nsACString &aTypeHeader,
1641
                                           nsACString &aCharset,
1642
                                           int32_t *aCharsetStart,
1643
                                           int32_t *aCharsetEnd,
1644
                                           bool *aHadCharset)
1645
0
{
1646
0
    nsAutoCString ignored;
1647
0
    net_ParseContentType(aTypeHeader, ignored, aCharset, aHadCharset,
1648
0
                         aCharsetStart, aCharsetEnd);
1649
0
    if (*aHadCharset && *aCharsetStart == *aCharsetEnd) {
1650
0
        *aHadCharset = false;
1651
0
    }
1652
0
    return NS_OK;
1653
0
}
1654
1655
// parse policyString to policy enum value (see ReferrerPolicy.h)
1656
NS_IMETHODIMP
1657
nsIOService::ParseAttributePolicyString(const nsAString& policyString,
1658
                                                uint32_t *outPolicyEnum)
1659
0
{
1660
0
  NS_ENSURE_ARG(outPolicyEnum);
1661
0
  *outPolicyEnum = (uint32_t)AttributeReferrerPolicyFromString(policyString);
1662
0
  return NS_OK;
1663
0
}
1664
1665
// nsISpeculativeConnect
1666
class IOServiceProxyCallback final : public nsIProtocolProxyCallback
1667
{
1668
0
    ~IOServiceProxyCallback() = default;
1669
1670
public:
1671
    NS_DECL_ISUPPORTS
1672
    NS_DECL_NSIPROTOCOLPROXYCALLBACK
1673
1674
    IOServiceProxyCallback(nsIInterfaceRequestor *aCallbacks,
1675
                           nsIOService *aIOService)
1676
        : mCallbacks(aCallbacks)
1677
        , mIOService(aIOService)
1678
0
    { }
1679
1680
private:
1681
    RefPtr<nsIInterfaceRequestor> mCallbacks;
1682
    RefPtr<nsIOService>           mIOService;
1683
};
1684
1685
NS_IMPL_ISUPPORTS(IOServiceProxyCallback, nsIProtocolProxyCallback)
1686
1687
NS_IMETHODIMP
1688
IOServiceProxyCallback::OnProxyAvailable(nsICancelable *request, nsIChannel *channel,
1689
                                         nsIProxyInfo *pi, nsresult status)
1690
0
{
1691
0
    // Checking proxy status for speculative connect
1692
0
    nsAutoCString type;
1693
0
    if (NS_SUCCEEDED(status) && pi &&
1694
0
        NS_SUCCEEDED(pi->GetType(type)) &&
1695
0
        !type.EqualsLiteral("direct")) {
1696
0
        // proxies dont do speculative connect
1697
0
        return NS_OK;
1698
0
    }
1699
0
1700
0
    nsCOMPtr<nsIURI> uri;
1701
0
    nsresult rv = channel->GetURI(getter_AddRefs(uri));
1702
0
    if (NS_FAILED(rv)) {
1703
0
        return NS_OK;
1704
0
    }
1705
0
1706
0
    nsAutoCString scheme;
1707
0
    rv = uri->GetScheme(scheme);
1708
0
    if (NS_FAILED(rv))
1709
0
        return NS_OK;
1710
0
1711
0
    nsCOMPtr<nsIProtocolHandler> handler;
1712
0
    rv = mIOService->GetProtocolHandler(scheme.get(),
1713
0
                                        getter_AddRefs(handler));
1714
0
    if (NS_FAILED(rv))
1715
0
        return NS_OK;
1716
0
1717
0
    nsCOMPtr<nsISpeculativeConnect> speculativeHandler =
1718
0
        do_QueryInterface(handler);
1719
0
    if (!speculativeHandler)
1720
0
        return NS_OK;
1721
0
1722
0
    nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
1723
0
    nsCOMPtr<nsIPrincipal> principal;
1724
0
    if (loadInfo) {
1725
0
      principal = loadInfo->LoadingPrincipal();
1726
0
    }
1727
0
1728
0
    nsLoadFlags loadFlags = 0;
1729
0
    channel->GetLoadFlags(&loadFlags);
1730
0
    if (loadFlags & nsIRequest::LOAD_ANONYMOUS) {
1731
0
        speculativeHandler->SpeculativeAnonymousConnect2(uri, principal, mCallbacks);
1732
0
    } else {
1733
0
        speculativeHandler->SpeculativeConnect2(uri, principal, mCallbacks);
1734
0
    }
1735
0
1736
0
    return NS_OK;
1737
0
}
1738
1739
nsresult
1740
nsIOService::SpeculativeConnectInternal(nsIURI *aURI,
1741
                                        nsIPrincipal *aPrincipal,
1742
                                        nsIInterfaceRequestor *aCallbacks,
1743
                                        bool aAnonymous)
1744
0
{
1745
0
    NS_ENSURE_ARG(aURI);
1746
0
1747
0
    bool isHTTP, isHTTPS;
1748
0
    if (!(NS_SUCCEEDED(aURI->SchemeIs("http", &isHTTP)) && isHTTP) &&
1749
0
        !(NS_SUCCEEDED(aURI->SchemeIs("https", &isHTTPS)) && isHTTPS)) {
1750
0
        // We don't speculatively connect to non-HTTP[S] URIs.
1751
0
        return NS_OK;
1752
0
    }
1753
0
1754
0
    if (IsNeckoChild()) {
1755
0
        ipc::URIParams params;
1756
0
        SerializeURI(aURI, params);
1757
0
        gNeckoChild->SendSpeculativeConnect(params,
1758
0
                                            IPC::Principal(aPrincipal),
1759
0
                                            aAnonymous);
1760
0
        return NS_OK;
1761
0
    }
1762
0
1763
0
    // Check for proxy information. If there is a proxy configured then a
1764
0
    // speculative connect should not be performed because the potential
1765
0
    // reward is slim with tcp peers closely located to the browser.
1766
0
    nsresult rv;
1767
0
    nsCOMPtr<nsIProtocolProxyService> pps =
1768
0
            do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv);
1769
0
    NS_ENSURE_SUCCESS(rv, rv);
1770
0
1771
0
    nsCOMPtr<nsIPrincipal> loadingPrincipal = aPrincipal;
1772
0
1773
0
    NS_ASSERTION(aPrincipal, "We expect passing a principal here.");
1774
0
1775
0
    // If the principal is given, we use this principal directly. Otherwise,
1776
0
    // we fallback to use the system principal.
1777
0
    if (!aPrincipal) {
1778
0
        loadingPrincipal = nsContentUtils::GetSystemPrincipal();
1779
0
    }
1780
0
1781
0
    // dummy channel used to create a TCP connection.
1782
0
    // we perform security checks on the *real* channel, responsible
1783
0
    // for any network loads. this real channel just checks the TCP
1784
0
    // pool if there is an available connection created by the
1785
0
    // channel we create underneath - hence it's safe to use
1786
0
    // the systemPrincipal as the loadingPrincipal for this channel.
1787
0
    nsCOMPtr<nsIChannel> channel;
1788
0
    rv = NewChannelFromURI2(aURI,
1789
0
                            nullptr, // aLoadingNode,
1790
0
                            loadingPrincipal,
1791
0
                            nullptr, //aTriggeringPrincipal,
1792
0
                            nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
1793
0
                            nsIContentPolicy::TYPE_SPECULATIVE,
1794
0
                            getter_AddRefs(channel));
1795
0
    NS_ENSURE_SUCCESS(rv, rv);
1796
0
1797
0
    if (aAnonymous) {
1798
0
        nsLoadFlags loadFlags = 0;
1799
0
        channel->GetLoadFlags(&loadFlags);
1800
0
        loadFlags |= nsIRequest::LOAD_ANONYMOUS;
1801
0
        channel->SetLoadFlags(loadFlags);
1802
0
    }
1803
0
1804
0
    nsCOMPtr<nsICancelable> cancelable;
1805
0
    RefPtr<IOServiceProxyCallback> callback =
1806
0
        new IOServiceProxyCallback(aCallbacks, this);
1807
0
    nsCOMPtr<nsIProtocolProxyService2> pps2 = do_QueryInterface(pps);
1808
0
    if (pps2) {
1809
0
        return pps2->AsyncResolve2(channel, 0, callback, nullptr,
1810
0
                                   getter_AddRefs(cancelable));
1811
0
    }
1812
0
    return pps->AsyncResolve(channel, 0, callback, nullptr,
1813
0
                             getter_AddRefs(cancelable));
1814
0
}
1815
1816
NS_IMETHODIMP
1817
nsIOService::SpeculativeConnect(nsIURI *aURI,
1818
                                nsIInterfaceRequestor *aCallbacks)
1819
0
{
1820
0
    return SpeculativeConnectInternal(aURI, nullptr, aCallbacks, false);
1821
0
}
1822
1823
NS_IMETHODIMP
1824
nsIOService::SpeculativeConnect2(nsIURI *aURI,
1825
                                 nsIPrincipal *aPrincipal,
1826
                                 nsIInterfaceRequestor *aCallbacks)
1827
0
{
1828
0
    return SpeculativeConnectInternal(aURI, aPrincipal, aCallbacks, false);
1829
0
}
1830
1831
NS_IMETHODIMP
1832
nsIOService::SpeculativeAnonymousConnect(nsIURI *aURI,
1833
                                         nsIInterfaceRequestor *aCallbacks)
1834
0
{
1835
0
    return SpeculativeConnectInternal(aURI, nullptr, aCallbacks, true);
1836
0
}
1837
1838
NS_IMETHODIMP
1839
nsIOService::SpeculativeAnonymousConnect2(nsIURI *aURI,
1840
                                          nsIPrincipal *aPrincipal,
1841
                                          nsIInterfaceRequestor *aCallbacks)
1842
0
{
1843
0
    return SpeculativeConnectInternal(aURI, aPrincipal, aCallbacks, true);
1844
0
}
1845
1846
/*static*/ bool
1847
nsIOService::IsDataURIUniqueOpaqueOrigin()
1848
0
{
1849
0
  return sIsDataURIUniqueOpaqueOrigin;
1850
0
}
1851
1852
/*static*/ bool
1853
nsIOService::BlockToplevelDataUriNavigations()
1854
0
{
1855
0
  return sBlockToplevelDataUriNavigations;
1856
0
}
1857
1858
/*static*/ bool
1859
nsIOService::BlockFTPSubresources()
1860
5
{
1861
5
  return sBlockFTPSubresources;
1862
5
}
1863
1864
NS_IMETHODIMP
1865
nsIOService::NotImplemented()
1866
0
{
1867
0
  return NS_ERROR_NOT_IMPLEMENTED;
1868
0
}
1869
1870
} // namespace net
1871
} // namespace mozilla