Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/netwerk/protocol/http/nsHttpHandler.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/* vim:set ts=4 sw=4 sts=4 et cin: */
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
// HttpLog.h should generally be included first
8
#include "HttpLog.h"
9
10
#include "prsystem.h"
11
12
#include "nsError.h"
13
#include "nsHttp.h"
14
#include "nsHttpHandler.h"
15
#include "nsHttpChannel.h"
16
#include "nsHttpAuthCache.h"
17
#include "nsStandardURL.h"
18
#include "nsIDOMWindow.h"
19
#include "nsINetworkProperties.h"
20
#include "nsIHttpChannel.h"
21
#include "nsIStandardURL.h"
22
#include "LoadContextInfo.h"
23
#include "nsCategoryManagerUtils.h"
24
#include "nsIPrefService.h"
25
#include "nsIPrefBranch.h"
26
#include "nsIPrefLocalizedString.h"
27
#include "nsISocketProviderService.h"
28
#include "nsISocketProvider.h"
29
#include "nsPrintfCString.h"
30
#include "nsCOMPtr.h"
31
#include "nsNetCID.h"
32
#include "mozilla/ClearOnShutdown.h"
33
#include "mozilla/Printf.h"
34
#include "mozilla/Sprintf.h"
35
#include "nsAsyncRedirectVerifyHelper.h"
36
#include "nsSocketTransportService2.h"
37
#include "nsAlgorithm.h"
38
#include "ASpdySession.h"
39
#include "EventTokenBucket.h"
40
#include "Tickler.h"
41
#include "nsIXULAppInfo.h"
42
#include "nsICookieService.h"
43
#include "nsIObserverService.h"
44
#include "nsISiteSecurityService.h"
45
#include "nsIStreamConverterService.h"
46
#include "nsCRT.h"
47
#include "nsIMemoryReporter.h"
48
#include "nsIParentalControlsService.h"
49
#include "nsPIDOMWindow.h"
50
#include "nsINetworkLinkService.h"
51
#include "nsHttpChannelAuthProvider.h"
52
#include "nsServiceManagerUtils.h"
53
#include "nsComponentManagerUtils.h"
54
#include "nsSocketTransportService2.h"
55
#include "nsIOService.h"
56
#include "nsISupportsPrimitives.h"
57
#include "nsIXULRuntime.h"
58
#include "nsCharSeparatedTokenizer.h"
59
#include "nsRFPService.h"
60
#include "rust-helper/src/helper.h"
61
62
#include "mozilla/net/NeckoChild.h"
63
#include "mozilla/net/NeckoParent.h"
64
#include "mozilla/ipc/URIUtils.h"
65
#include "mozilla/Telemetry.h"
66
#include "mozilla/Unused.h"
67
#include "mozilla/BasePrincipal.h"
68
69
#include "mozilla/dom/ContentParent.h"
70
#include "mozilla/dom/Navigator.h"
71
72
#include "nsNSSComponent.h"
73
74
#if defined(XP_UNIX)
75
#include <sys/utsname.h>
76
#endif
77
78
#if defined(XP_WIN)
79
#include <windows.h>
80
#include "mozilla/WindowsVersion.h"
81
#endif
82
83
#if defined(XP_MACOSX)
84
#include <CoreServices/CoreServices.h>
85
#include "nsCocoaFeatures.h"
86
#endif
87
88
#ifdef MOZ_TASK_TRACER
89
#include "GeckoTaskTracer.h"
90
#endif
91
92
//-----------------------------------------------------------------------------
93
#include "mozilla/net/HttpChannelChild.h"
94
95
96
2
#define UA_PREF_PREFIX          "general.useragent."
97
#ifdef XP_WIN
98
#define UA_SPARE_PLATFORM
99
#endif
100
101
81
#define HTTP_PREF_PREFIX        "network.http."
102
0
#define INTL_ACCEPT_LANGUAGES   "intl.accept_languages"
103
1
#define BROWSER_PREF_PREFIX     "browser.cache."
104
1
#define DONOTTRACK_HEADER_ENABLED "privacy.donottrackheader.enabled"
105
1
#define H2MANDATORY_SUITE        "security.ssl3.ecdhe_rsa_aes_128_gcm_sha256"
106
1
#define TELEMETRY_ENABLED        "toolkit.telemetry.enabled"
107
1
#define ALLOW_EXPERIMENTS        "network.allow-experiments"
108
1
#define SAFE_HINT_HEADER_VALUE   "safeHint.enabled"
109
#define SECURITY_PREFIX          "security."
110
111
1
#define TCP_FAST_OPEN_ENABLE         "network.tcp.tcp_fastopen_enable"
112
1
#define TCP_FAST_OPEN_FAILURE_LIMIT  "network.tcp.tcp_fastopen_consecutive_failure_limit"
113
1
#define TCP_FAST_OPEN_STALLS_LIMIT   "network.tcp.tcp_fastopen_http_stalls_limit"
114
1
#define TCP_FAST_OPEN_STALLS_IDLE    "network.tcp.tcp_fastopen_http_check_for_stalls_only_if_idle_for"
115
1
#define TCP_FAST_OPEN_STALLS_TIMEOUT "network.tcp.tcp_fastopen_http_stalls_timeout"
116
117
2
#define UA_PREF(_pref) UA_PREF_PREFIX _pref
118
81
#define HTTP_PREF(_pref) HTTP_PREF_PREFIX _pref
119
1
#define BROWSER_PREF(_pref) BROWSER_PREF_PREFIX _pref
120
121
11.5k
#define NS_HTTP_PROTOCOL_FLAGS (URI_STD | ALLOWS_PROXY | ALLOWS_PROXY_HTTP | URI_LOADABLE_BY_ANYONE)
122
123
//-----------------------------------------------------------------------------
124
125
using mozilla::Telemetry::LABELS_NETWORK_HTTP_REDIRECT_TO_SCHEME;
126
127
namespace mozilla {
128
namespace net {
129
130
LazyLogModule gHttpLog("nsHttp");
131
132
static nsresult
133
NewURI(const nsACString &aSpec,
134
       const char *aCharset,
135
       nsIURI *aBaseURI,
136
       int32_t aDefaultPort,
137
       nsIURI **aURI)
138
1.06M
{
139
1.06M
    nsCOMPtr<nsIURI> base(aBaseURI);
140
1.06M
    return NS_MutateURI(new nsStandardURL::Mutator())
141
1.06M
        .Apply(NS_MutatorMethod(&nsIStandardURLMutator::Init,
142
1.06M
                                nsIStandardURL::URLTYPE_AUTHORITY,
143
1.06M
                                aDefaultPort, nsCString(aSpec), aCharset,
144
1.06M
                                base, nullptr))
145
1.06M
        .Finalize(aURI);
146
1.06M
}
147
148
#ifdef ANDROID
149
static nsCString
150
GetDeviceModelId() {
151
    // Assumed to be running on the main thread
152
    // We need the device property in either case
153
    nsAutoCString deviceModelId;
154
    nsCOMPtr<nsIPropertyBag2> infoService = do_GetService("@mozilla.org/system-info;1");
155
    MOZ_ASSERT(infoService, "Could not find a system info service");
156
    nsAutoString androidDevice;
157
    nsresult rv = infoService->GetPropertyAsAString(NS_LITERAL_STRING("device"), androidDevice);
158
    if (NS_SUCCEEDED(rv)) {
159
        deviceModelId = NS_LossyConvertUTF16toASCII(androidDevice);
160
    }
161
    nsAutoCString deviceString;
162
    rv = Preferences::GetCString(UA_PREF("device_string"), deviceString);
163
    if (NS_SUCCEEDED(rv)) {
164
        deviceString.Trim(" ", true, true);
165
        deviceString.ReplaceSubstring(NS_LITERAL_CSTRING("%DEVICEID%"), deviceModelId);
166
        return deviceString;
167
    }
168
    return deviceModelId;
169
}
170
#endif
171
172
//-----------------------------------------------------------------------------
173
// nsHttpHandler <public>
174
//-----------------------------------------------------------------------------
175
176
StaticRefPtr<nsHttpHandler> gHttpHandler;
177
178
/* static */ already_AddRefed<nsHttpHandler>
179
nsHttpHandler::GetInstance()
180
1
{
181
1
    if (!gHttpHandler) {
182
1
        gHttpHandler = new nsHttpHandler();
183
1
        DebugOnly<nsresult> rv = gHttpHandler->Init();
184
1
        MOZ_ASSERT(NS_SUCCEEDED(rv));
185
1
        ClearOnShutdown(&gHttpHandler);
186
1
    }
187
1
    RefPtr<nsHttpHandler> httpHandler = gHttpHandler;
188
1
    return httpHandler.forget();
189
1
}
190
191
nsHttpHandler::nsHttpHandler()
192
    : mHttpVersion(HttpVersion::v1_1)
193
    , mProxyHttpVersion(HttpVersion::v1_1)
194
    , mCapabilities(NS_HTTP_ALLOW_KEEPALIVE)
195
    , mReferrerLevel(0xff) // by default we always send a referrer
196
    , mSpoofReferrerSource(false)
197
    , mHideOnionReferrerSource(false)
198
    , mReferrerTrimmingPolicy(0)
199
    , mReferrerXOriginTrimmingPolicy(0)
200
    , mReferrerXOriginPolicy(0)
201
    , mFastFallbackToIPv4(false)
202
    , mIdleTimeout(PR_SecondsToInterval(10))
203
    , mSpdyTimeout(PR_SecondsToInterval(180))
204
    , mResponseTimeout(PR_SecondsToInterval(300))
205
    , mResponseTimeoutEnabled(false)
206
    , mNetworkChangedTimeout(5000)
207
    , mMaxRequestAttempts(6)
208
    , mMaxRequestDelay(10)
209
    , mIdleSynTimeout(250)
210
    , mFallbackSynTimeout(5)
211
    , mH2MandatorySuiteEnabled(false)
212
    , mMaxUrgentExcessiveConns(3)
213
    , mMaxConnections(24)
214
    , mMaxPersistentConnectionsPerServer(2)
215
    , mMaxPersistentConnectionsPerProxy(4)
216
    , mThrottleEnabled(true)
217
    , mThrottleVersion(2)
218
    , mThrottleSuspendFor(3000)
219
    , mThrottleResumeFor(200)
220
    , mThrottleReadLimit(8000)
221
    , mThrottleReadInterval(500)
222
    , mThrottleHoldTime(600)
223
    , mThrottleMaxTime(3000)
224
    , mSendWindowSize(1024)
225
    , mUrgentStartEnabled(true)
226
    , mTailBlockingEnabled(true)
227
    , mTailDelayQuantum(600)
228
    , mTailDelayQuantumAfterDCL(100)
229
    , mTailDelayMax(6000)
230
    , mTailTotalMax(0)
231
    , mRedirectionLimit(10)
232
    , mPhishyUserPassLength(1)
233
    , mQoSBits(0x00)
234
    , mEnforceAssocReq(false)
235
    , mLastUniqueID(NowInSeconds())
236
    , mSessionStartTime(0)
237
    , mLegacyAppName("Mozilla")
238
    , mLegacyAppVersion("5.0")
239
    , mProduct("Gecko")
240
    , mCompatFirefoxEnabled(false)
241
    , mUserAgentIsDirty(true)
242
    , mAcceptLanguagesIsDirty(true)
243
    , mPromptTempRedirect(true)
244
    , mEnablePersistentHttpsCaching(false)
245
    , mDoNotTrackEnabled(false)
246
    , mSafeHintEnabled(false)
247
    , mParentalControlEnabled(false)
248
    , mHandlerActive(false)
249
    , mTelemetryEnabled(false)
250
    , mAllowExperiments(true)
251
    , mDebugObservations(false)
252
    , mEnableSpdy(false)
253
    , mHttp2Enabled(true)
254
    , mUseH2Deps(true)
255
    , mEnforceHttp2TlsProfile(true)
256
    , mCoalesceSpdy(true)
257
    , mSpdyPersistentSettings(false)
258
    , mAllowPush(true)
259
    , mEnableAltSvc(false)
260
    , mEnableAltSvcOE(false)
261
    , mEnableOriginExtension(false)
262
    , mSpdySendingChunkSize(ASpdySession::kSendingChunkSize)
263
    , mSpdySendBufferSize(ASpdySession::kTCPSendBufferSize)
264
    , mSpdyPushAllowance(131072) // match default pref
265
    , mSpdyPullAllowance(ASpdySession::kInitialRwin)
266
    , mDefaultSpdyConcurrent(ASpdySession::kDefaultMaxConcurrent)
267
    , mSpdyPingThreshold(PR_SecondsToInterval(58))
268
    , mSpdyPingTimeout(PR_SecondsToInterval(8))
269
    , mConnectTimeout(90000)
270
    , mTLSHandshakeTimeout(30000)
271
    , mParallelSpeculativeConnectLimit(6)
272
    , mSpeculativeConnectEnabled(true)
273
    , mRequestTokenBucketEnabled(true)
274
    , mRequestTokenBucketMinParallelism(6)
275
    , mRequestTokenBucketHz(100)
276
    , mRequestTokenBucketBurst(32)
277
    , mCriticalRequestPrioritization(true)
278
    , mTCPKeepaliveShortLivedEnabled(false)
279
    , mTCPKeepaliveShortLivedTimeS(60)
280
    , mTCPKeepaliveShortLivedIdleTimeS(10)
281
    , mTCPKeepaliveLongLivedEnabled(false)
282
    , mTCPKeepaliveLongLivedIdleTimeS(600)
283
    , mEnforceH1Framing(FRAMECHECK_BARELY)
284
    , mDefaultHpackBuffer(4096)
285
    , mMaxHttpResponseHeaderSize(393216)
286
    , mFocusedWindowTransactionRatio(0.9f)
287
    , mUseFastOpen(true)
288
    , mFastOpenConsecutiveFailureLimit(5)
289
    , mFastOpenConsecutiveFailureCounter(0)
290
    , mFastOpenStallsLimit(3)
291
    , mFastOpenStallsCounter(0)
292
    , mFastOpenStallsIdleTime(10)
293
    , mFastOpenStallsTimeout(20)
294
    , mActiveTabPriority(true)
295
    , mProcessId(0)
296
    , mNextChannelId(1)
297
    , mLastActiveTabLoadOptimizationLock("nsHttpConnectionMgr::LastActiveTabLoadOptimization")
298
1
{
299
1
    LOG(("Creating nsHttpHandler [this=%p].\n", this));
300
1
301
1
    mUserAgentOverride.SetIsVoid(true);
302
1
303
1
    MOZ_ASSERT(!gHttpHandler, "HTTP handler already created!");
304
1
305
1
    nsCOMPtr<nsIXULRuntime> runtime = do_GetService("@mozilla.org/xre/runtime;1");
306
1
    if (runtime) {
307
1
        runtime->GetProcessID(&mProcessId);
308
1
    }
309
1
    SetFastOpenOSSupport();
310
1
}
311
312
void
313
nsHttpHandler::SetFastOpenOSSupport()
314
1
{
315
1
    mFastOpenSupported = false;
316
#if !defined(XP_WIN) && !defined(XP_LINUX) && !defined(ANDROID) && !defined(HAS_CONNECTX)
317
    return;
318
#elif defined(XP_WIN)
319
    mFastOpenSupported = IsWindows10BuildOrLater(16299);
320
321
    if (mFastOpenSupported) {
322
        // We have some problems with lavasoft software and tcp fast open.
323
        if (GetModuleHandleW(L"pmls64.dll") || GetModuleHandleW(L"rlls64.dll")) {
324
            mFastOpenSupported = false;
325
        }
326
    }
327
#else
328
329
1
    nsAutoCString version;
330
1
    nsresult rv;
331
#ifdef ANDROID
332
    nsCOMPtr<nsIPropertyBag2> infoService =
333
        do_GetService("@mozilla.org/system-info;1");
334
    MOZ_ASSERT(infoService, "Could not find a system info service");
335
    rv = infoService->GetPropertyAsACString(
336
        NS_LITERAL_STRING("sdk_version"), version);
337
#else
338
    char buf[SYS_INFO_BUFFER_LENGTH];
339
1
    if (PR_GetSystemInfo(PR_SI_RELEASE, buf, sizeof(buf)) == PR_SUCCESS) {
340
1
        version = buf;
341
1
        rv = NS_OK;
342
1
    } else {
343
0
        rv = NS_ERROR_FAILURE;
344
0
    }
345
1
#endif
346
1
347
1
    LOG(("nsHttpHandler::SetFastOpenOSSupport version %s", version.get()));
348
1
349
1
    if (NS_SUCCEEDED(rv)) {
350
1
        // set min version minus 1.
351
#if XP_MACOSX
352
        int min_version[] = {17, 5}; // High Sierra 10.13.4
353
#elif ANDROID
354
        int min_version[] = {4, 4};
355
#elif XP_LINUX
356
        int min_version[] = {3, 6};
357
1
#endif
358
1
        int inx = 0;
359
1
        nsCCharSeparatedTokenizer tokenizer(version, '.');
360
1
        while ((inx < 2) && tokenizer.hasMoreTokens()) {
361
1
            nsAutoCString token(tokenizer.nextToken());
362
1
            const char* nondigit = NS_strspnp("0123456789", token.get());
363
1
            if (nondigit && *nondigit) {
364
0
                break;
365
0
            }
366
1
            nsresult rv;
367
1
            int32_t ver = token.ToInteger(&rv);
368
1
            if (NS_FAILED(rv)) {
369
0
                break;
370
0
            }
371
1
            if (ver > min_version[inx]) {
372
1
                mFastOpenSupported = true;
373
1
                break;
374
1
            } else if (ver == min_version[inx] && inx == 1) {
375
0
                mFastOpenSupported = true;
376
0
            } else if (ver < min_version[inx]) {
377
0
                break;
378
0
            }
379
0
            inx++;
380
0
        }
381
1
    }
382
1
#endif
383
1
    LOG(("nsHttpHandler::SetFastOpenOSSupport %s supported.\n",
384
1
         mFastOpenSupported ? "" : "not"));
385
1
}
386
387
void
388
nsHttpHandler::EnsureUAOverridesInit()
389
0
{
390
0
    MOZ_ASSERT(XRE_IsParentProcess());
391
0
    MOZ_ASSERT(NS_IsMainThread());
392
0
393
0
    nsresult rv;
394
0
    nsCOMPtr<nsISupports> bootstrapper
395
0
        = do_GetService("@mozilla.org/network/ua-overrides-bootstrapper;1", &rv);
396
0
    MOZ_ASSERT(bootstrapper);
397
0
    MOZ_ASSERT(NS_SUCCEEDED(rv));
398
0
}
399
400
nsHttpHandler::~nsHttpHandler()
401
0
{
402
0
    LOG(("Deleting nsHttpHandler [this=%p]\n", this));
403
0
404
0
    // make sure the connection manager is shutdown
405
0
    if (mConnMgr) {
406
0
        nsresult rv = mConnMgr->Shutdown();
407
0
        if (NS_FAILED(rv)) {
408
0
            LOG(("nsHttpHandler [this=%p] "
409
0
                 "failed to shutdown connection manager (%08x)\n",
410
0
                 this, static_cast<uint32_t>(rv)));
411
0
        }
412
0
        mConnMgr = nullptr;
413
0
    }
414
0
415
0
    // Note: don't call NeckoChild::DestroyNeckoChild() here, as it's too late
416
0
    // and it'll segfault.  NeckoChild will get cleaned up by process exit.
417
0
418
0
    nsHttp::DestroyAtomTable();
419
0
}
420
421
static const char* gCallbackPrefs[] = {
422
    HTTP_PREF_PREFIX,
423
    UA_PREF_PREFIX,
424
    INTL_ACCEPT_LANGUAGES,
425
    BROWSER_PREF("disk_cache_ssl"),
426
    DONOTTRACK_HEADER_ENABLED,
427
    TELEMETRY_ENABLED,
428
    H2MANDATORY_SUITE,
429
    HTTP_PREF("tcp_keepalive.short_lived_connections"),
430
    HTTP_PREF("tcp_keepalive.long_lived_connections"),
431
    SAFE_HINT_HEADER_VALUE,
432
    SECURITY_PREFIX,
433
    TCP_FAST_OPEN_ENABLE,
434
    TCP_FAST_OPEN_FAILURE_LIMIT,
435
    TCP_FAST_OPEN_STALLS_LIMIT,
436
    TCP_FAST_OPEN_STALLS_IDLE,
437
    TCP_FAST_OPEN_STALLS_TIMEOUT,
438
    nullptr,
439
};
440
441
nsresult
442
nsHttpHandler::Init()
443
1
{
444
1
    nsresult rv;
445
1
446
1
    LOG(("nsHttpHandler::Init\n"));
447
1
    MOZ_ASSERT(NS_IsMainThread());
448
1
449
1
    rv = nsHttp::CreateAtomTable();
450
1
    if (NS_FAILED(rv))
451
1
        return rv;
452
1
453
1
    nsCOMPtr<nsIIOService> service = do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
454
1
    if (NS_FAILED(rv)) {
455
0
        NS_WARNING("unable to continue without io service");
456
0
        return rv;
457
0
    }
458
1
    mIOService = new nsMainThreadPtrHolder<nsIIOService>(
459
1
      "nsHttpHandler::mIOService", service);
460
1
461
1
    if (IsNeckoChild())
462
0
        NeckoChild::InitNeckoChild();
463
1
464
1
    InitUserAgentComponents();
465
1
466
1
    // This perference is only used in parent process.
467
1
    if (!IsNeckoChild()) {
468
1
        mActiveTabPriority =
469
1
            Preferences::GetBool(HTTP_PREF("active_tab_priority"), true);
470
1
    }
471
1
472
1
    // monitor some preference changes
473
1
    Preferences::RegisterPrefixCallbacks(
474
1
        PREF_CHANGE_METHOD(nsHttpHandler::PrefsChanged),
475
1
        gCallbackPrefs,
476
1
        this);
477
1
    PrefsChanged(nullptr);
478
1
479
1
    mMisc.AssignLiteral("rv:" MOZILLA_UAVERSION);
480
1
481
1
    mCompatFirefox.AssignLiteral("Firefox/" MOZILLA_UAVERSION);
482
1
483
1
    nsCOMPtr<nsIXULAppInfo> appInfo =
484
1
        do_GetService("@mozilla.org/xre/app-info;1");
485
1
486
1
    mAppName.AssignLiteral(MOZ_APP_UA_NAME);
487
1
    if (mAppName.Length() == 0 && appInfo) {
488
1
        // Try to get the UA name from appInfo, falling back to the name
489
1
        appInfo->GetUAName(mAppName);
490
1
        if (mAppName.Length() == 0) {
491
1
          appInfo->GetName(mAppName);
492
1
        }
493
1
        appInfo->GetVersion(mAppVersion);
494
1
        mAppName.StripChars(R"( ()<>@,;:\"/[]?={})");
495
1
    } else {
496
0
        mAppVersion.AssignLiteral(MOZ_APP_UA_VERSION);
497
0
    }
498
1
499
1
    // Generating the spoofed User Agent for fingerprinting resistance.
500
1
    rv = nsRFPService::GetSpoofedUserAgent(mSpoofedUserAgent);
501
1
    if (NS_FAILED(rv)) {
502
0
      // Empty mSpoofedUserAgent to make sure the unsuccessful spoofed UA string
503
0
      // will not be used anywhere.
504
0
      mSpoofedUserAgent.Truncate();
505
0
    }
506
1
507
1
    mSessionStartTime = NowInSeconds();
508
1
    mHandlerActive = true;
509
1
510
1
    rv = InitConnectionMgr();
511
1
    if (NS_FAILED(rv)) return rv;
512
1
513
1
    mRequestContextService =
514
1
        do_GetService("@mozilla.org/network/request-context-service;1");
515
1
516
#if defined(ANDROID)
517
    mProductSub.AssignLiteral(MOZILLA_UAVERSION);
518
#else
519
1
    mProductSub.AssignLiteral(LEGACY_BUILD_ID);
520
1
#endif
521
1
522
#if DEBUG
523
    // dump user agent prefs
524
    LOG(("> legacy-app-name = %s\n", mLegacyAppName.get()));
525
    LOG(("> legacy-app-version = %s\n", mLegacyAppVersion.get()));
526
    LOG(("> platform = %s\n", mPlatform.get()));
527
    LOG(("> oscpu = %s\n", mOscpu.get()));
528
    LOG(("> misc = %s\n", mMisc.get()));
529
    LOG(("> product = %s\n", mProduct.get()));
530
    LOG(("> product-sub = %s\n", mProductSub.get()));
531
    LOG(("> app-name = %s\n", mAppName.get()));
532
    LOG(("> app-version = %s\n", mAppVersion.get()));
533
    LOG(("> compat-firefox = %s\n", mCompatFirefox.get()));
534
    LOG(("> user-agent = %s\n", UserAgent().get()));
535
#endif
536
537
1
    // Startup the http category
538
1
    // Bring alive the objects in the http-protocol-startup category
539
1
    NS_CreateServicesFromCategory(NS_HTTP_STARTUP_CATEGORY,
540
1
                                  static_cast<nsISupports*>(static_cast<void*>(this)),
541
1
                                  NS_HTTP_STARTUP_TOPIC);
542
1
543
1
    nsCOMPtr<nsIObserverService> obsService = services::GetObserverService();
544
1
    if (obsService) {
545
1
        // register the handler object as a weak callback as we don't need to worry
546
1
        // about shutdown ordering.
547
1
        obsService->AddObserver(this, "profile-change-net-teardown", true);
548
1
        obsService->AddObserver(this, "profile-change-net-restore", true);
549
1
        obsService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, true);
550
1
        obsService->AddObserver(this, "net:clear-active-logins", true);
551
1
        obsService->AddObserver(this, "net:prune-dead-connections", true);
552
1
        // Sent by the TorButton add-on in the Tor Browser
553
1
        obsService->AddObserver(this, "net:prune-all-connections", true);
554
1
        obsService->AddObserver(this, "net:cancel-all-connections", true);
555
1
        obsService->AddObserver(this, "last-pb-context-exited", true);
556
1
        obsService->AddObserver(this, "browser:purge-session-history", true);
557
1
        obsService->AddObserver(this, NS_NETWORK_LINK_TOPIC, true);
558
1
        obsService->AddObserver(this, "application-background", true);
559
1
        obsService->AddObserver(this, "psm:user-certificate-added", true);
560
1
        obsService->AddObserver(this, "psm:user-certificate-deleted", true);
561
1
        obsService->AddObserver(this, "intl:app-locales-changed", true);
562
1
563
1
        if (!IsNeckoChild()) {
564
1
            obsService->AddObserver(this,
565
1
                                    "net:current-toplevel-outer-content-windowid",
566
1
                                    true);
567
1
        }
568
1
569
1
        if (mFastOpenSupported) {
570
1
            obsService->AddObserver(this, "captive-portal-login", true);
571
1
            obsService->AddObserver(this, "captive-portal-login-success", true);
572
1
        }
573
1
574
1
        // disabled as its a nop right now
575
1
        // obsService->AddObserver(this, "net:failed-to-process-uri-content", true);
576
1
    }
577
1
578
1
    MakeNewRequestTokenBucket();
579
1
    mWifiTickler = new Tickler();
580
1
    if (NS_FAILED(mWifiTickler->Init()))
581
1
        mWifiTickler = nullptr;
582
1
583
1
    nsCOMPtr<nsIParentalControlsService> pc = do_CreateInstance("@mozilla.org/parental-controls-service;1");
584
1
    if (pc) {
585
1
        pc->GetParentalControlsEnabled(&mParentalControlEnabled);
586
1
    }
587
1
    return NS_OK;
588
1
}
589
590
void
591
nsHttpHandler::MakeNewRequestTokenBucket()
592
2
{
593
2
    LOG(("nsHttpHandler::MakeNewRequestTokenBucket this=%p child=%d\n",
594
2
         this, IsNeckoChild()));
595
2
    if (!mConnMgr || IsNeckoChild()) {
596
1
        return;
597
1
    }
598
1
    RefPtr<EventTokenBucket> tokenBucket =
599
1
        new EventTokenBucket(RequestTokenBucketHz(), RequestTokenBucketBurst());
600
1
    // NOTE The thread or socket may be gone already.
601
1
    nsresult rv = mConnMgr->UpdateRequestTokenBucket(tokenBucket);
602
1
    if (NS_FAILED(rv)) {
603
0
        LOG(("    failed to update request token bucket\n"));
604
0
    }
605
1
}
606
607
nsresult
608
nsHttpHandler::InitConnectionMgr()
609
1
{
610
1
    // Init ConnectionManager only on parent!
611
1
    if (IsNeckoChild()) {
612
0
        return NS_OK;
613
0
    }
614
1
615
1
    nsresult rv;
616
1
617
1
    if (!mConnMgr) {
618
1
        mConnMgr = new nsHttpConnectionMgr();
619
1
    }
620
1
621
1
    rv = mConnMgr->Init(mMaxUrgentExcessiveConns,
622
1
                        mMaxConnections,
623
1
                        mMaxPersistentConnectionsPerServer,
624
1
                        mMaxPersistentConnectionsPerProxy,
625
1
                        mMaxRequestDelay,
626
1
                        mThrottleEnabled,
627
1
                        mThrottleVersion,
628
1
                        mThrottleSuspendFor,
629
1
                        mThrottleResumeFor,
630
1
                        mThrottleReadLimit,
631
1
                        mThrottleReadInterval,
632
1
                        mThrottleHoldTime,
633
1
                        mThrottleMaxTime);
634
1
    return rv;
635
1
}
636
637
nsresult
638
nsHttpHandler::AddStandardRequestHeaders(nsHttpRequestHead *request, bool isSecure)
639
0
{
640
0
    nsresult rv;
641
0
642
0
    // Add the "User-Agent" header
643
0
    rv = request->SetHeader(nsHttp::User_Agent, UserAgent(),
644
0
                            false, nsHttpHeaderArray::eVarietyRequestDefault);
645
0
    if (NS_FAILED(rv)) return rv;
646
0
647
0
    // MIME based content negotiation lives!
648
0
    // Add the "Accept" header.  Note, this is set as an override because the
649
0
    // service worker expects to see it.  The other "default" headers are
650
0
    // hidden from service worker interception.
651
0
    rv = request->SetHeader(nsHttp::Accept, mAccept,
652
0
                            false, nsHttpHeaderArray::eVarietyRequestOverride);
653
0
    if (NS_FAILED(rv)) return rv;
654
0
655
0
    // Add the "Accept-Language" header.  This header is also exposed to the
656
0
    // service worker.
657
0
    if (mAcceptLanguagesIsDirty) {
658
0
        rv = SetAcceptLanguages();
659
0
        MOZ_ASSERT(NS_SUCCEEDED(rv));
660
0
    }
661
0
662
0
    // Add the "Accept-Language" header
663
0
    if (!mAcceptLanguages.IsEmpty()) {
664
0
        rv = request->SetHeader(nsHttp::Accept_Language, mAcceptLanguages,
665
0
                                false,
666
0
                                nsHttpHeaderArray::eVarietyRequestOverride);
667
0
        if (NS_FAILED(rv)) return rv;
668
0
    }
669
0
670
0
    // Add the "Accept-Encoding" header
671
0
    if (isSecure) {
672
0
        rv = request->SetHeader(nsHttp::Accept_Encoding, mHttpsAcceptEncodings,
673
0
                                false,
674
0
                                nsHttpHeaderArray::eVarietyRequestDefault);
675
0
    } else {
676
0
        rv = request->SetHeader(nsHttp::Accept_Encoding, mHttpAcceptEncodings,
677
0
                                false,
678
0
                                nsHttpHeaderArray::eVarietyRequestDefault);
679
0
    }
680
0
    if (NS_FAILED(rv)) return rv;
681
0
682
0
    // add the "Send Hint" header
683
0
    if (mSafeHintEnabled || mParentalControlEnabled) {
684
0
      rv = request->SetHeader(nsHttp::Prefer, NS_LITERAL_CSTRING("safe"),
685
0
                              false,
686
0
                              nsHttpHeaderArray::eVarietyRequestDefault);
687
0
      if (NS_FAILED(rv)) return rv;
688
0
    }
689
0
    return NS_OK;
690
0
}
691
692
nsresult
693
nsHttpHandler::AddConnectionHeader(nsHttpRequestHead *request,
694
                                   uint32_t caps)
695
0
{
696
0
    // RFC2616 section 19.6.2 states that the "Connection: keep-alive"
697
0
    // and "Keep-alive" request headers should not be sent by HTTP/1.1
698
0
    // user-agents.  But this is not a problem in practice, and the
699
0
    // alternative proxy-connection is worse. see 570283
700
0
701
0
    NS_NAMED_LITERAL_CSTRING(close, "close");
702
0
    NS_NAMED_LITERAL_CSTRING(keepAlive, "keep-alive");
703
0
704
0
    const nsLiteralCString *connectionType = &close;
705
0
    if (caps & NS_HTTP_ALLOW_KEEPALIVE) {
706
0
        connectionType = &keepAlive;
707
0
    }
708
0
709
0
    return request->SetHeader(nsHttp::Connection, *connectionType);
710
0
}
711
712
bool
713
nsHttpHandler::IsAcceptableEncoding(const char *enc, bool isSecure)
714
0
{
715
0
    if (!enc)
716
0
        return false;
717
0
718
0
    // we used to accept x-foo anytime foo was acceptable, but that's just
719
0
    // continuing bad behavior.. so limit it to known x-* patterns
720
0
    bool rv;
721
0
    if (isSecure) {
722
0
        rv = nsHttp::FindToken(mHttpsAcceptEncodings.get(), enc, HTTP_LWS ",") != nullptr;
723
0
    } else {
724
0
        rv = nsHttp::FindToken(mHttpAcceptEncodings.get(), enc, HTTP_LWS ",") != nullptr;
725
0
    }
726
0
    // gzip and deflate are inherently acceptable in modern HTTP - always
727
0
    // process them if a stream converter can also be found.
728
0
    if (!rv &&
729
0
        (!PL_strcasecmp(enc, "gzip") || !PL_strcasecmp(enc, "deflate") ||
730
0
         !PL_strcasecmp(enc, "x-gzip") || !PL_strcasecmp(enc, "x-deflate"))) {
731
0
        rv = true;
732
0
    }
733
0
    LOG(("nsHttpHandler::IsAceptableEncoding %s https=%d %d\n",
734
0
         enc, isSecure, rv));
735
0
    return rv;
736
0
}
737
738
void
739
nsHttpHandler::IncrementFastOpenConsecutiveFailureCounter()
740
0
{
741
0
    LOG(("nsHttpHandler::IncrementFastOpenConsecutiveFailureCounter - "
742
0
         "failed=%d failure_limit=%d", mFastOpenConsecutiveFailureCounter,
743
0
         mFastOpenConsecutiveFailureLimit));
744
0
    if (mFastOpenConsecutiveFailureCounter < mFastOpenConsecutiveFailureLimit) {
745
0
        mFastOpenConsecutiveFailureCounter++;
746
0
        if (mFastOpenConsecutiveFailureCounter == mFastOpenConsecutiveFailureLimit) {
747
0
            LOG(("nsHttpHandler::IncrementFastOpenConsecutiveFailureCounter - "
748
0
                 "Fast open failed too many times"));
749
0
        }
750
0
    }
751
0
}
752
753
void
754
nsHttpHandler::IncrementFastOpenStallsCounter()
755
0
{
756
0
  LOG(("nsHttpHandler::IncrementFastOpenStallsCounter - failed=%d "
757
0
        "failure_limit=%d", mFastOpenStallsCounter, mFastOpenStallsLimit));
758
0
  if (mFastOpenStallsCounter < mFastOpenStallsLimit) {
759
0
    mFastOpenStallsCounter++;
760
0
    if (mFastOpenStallsCounter == mFastOpenStallsLimit) {
761
0
      LOG(("nsHttpHandler::IncrementFastOpenStallsCounter - "
762
0
           "There are too many stalls involving TFO and TLS."));
763
0
    }
764
0
  }
765
0
}
766
767
nsresult
768
nsHttpHandler::GetStreamConverterService(nsIStreamConverterService **result)
769
0
{
770
0
    if (!mStreamConvSvc) {
771
0
        nsresult rv;
772
0
        nsCOMPtr<nsIStreamConverterService> service =
773
0
            do_GetService(NS_STREAMCONVERTERSERVICE_CONTRACTID, &rv);
774
0
        if (NS_FAILED(rv))
775
0
            return rv;
776
0
        mStreamConvSvc = new nsMainThreadPtrHolder<nsIStreamConverterService>(
777
0
          "nsHttpHandler::mStreamConvSvc", service);
778
0
    }
779
0
    *result = mStreamConvSvc;
780
0
    NS_ADDREF(*result);
781
0
    return NS_OK;
782
0
}
783
784
nsISiteSecurityService*
785
nsHttpHandler::GetSSService()
786
0
{
787
0
    if (!mSSService) {
788
0
        nsCOMPtr<nsISiteSecurityService> service = do_GetService(NS_SSSERVICE_CONTRACTID);
789
0
        mSSService = new nsMainThreadPtrHolder<nsISiteSecurityService>(
790
0
          "nsHttpHandler::mSSService", service);
791
0
    }
792
0
    return mSSService;
793
0
}
794
795
nsICookieService *
796
nsHttpHandler::GetCookieService()
797
0
{
798
0
    if (!mCookieService) {
799
0
        nsCOMPtr<nsICookieService> service = do_GetService(NS_COOKIESERVICE_CONTRACTID);
800
0
        mCookieService = new nsMainThreadPtrHolder<nsICookieService>(
801
0
          "nsHttpHandler::mCookieService", service);
802
0
    }
803
0
    return mCookieService;
804
0
}
805
806
nsresult
807
nsHttpHandler::GetIOService(nsIIOService** result)
808
0
{
809
0
    NS_ENSURE_ARG_POINTER(result);
810
0
811
0
    NS_ADDREF(*result = mIOService);
812
0
    return NS_OK;
813
0
}
814
815
uint32_t
816
nsHttpHandler::Get32BitsOfPseudoRandom()
817
0
{
818
0
    // only confirm rand seeding on socket thread
819
0
    MOZ_ASSERT(OnSocketThread(), "not on socket thread");
820
0
821
0
    // rand() provides different amounts of PRNG on different platforms.
822
0
    // 15 or 31 bits are common amounts.
823
0
824
0
    static_assert(RAND_MAX >= 0xfff, "RAND_MAX should be >= 12 bits");
825
0
826
#if RAND_MAX < 0xffffU
827
    return ((uint16_t) rand() << 20) |
828
            (((uint16_t) rand() & 0xfff) << 8) |
829
            ((uint16_t) rand() & 0xff);
830
#elif RAND_MAX < 0xffffffffU
831
    return ((uint16_t) rand() << 16) | ((uint16_t) rand() & 0xffff);
832
#else
833
    return (uint32_t) rand();
834
#endif
835
}
836
837
void
838
nsHttpHandler::NotifyObservers(nsIHttpChannel *chan, const char *event)
839
0
{
840
0
    LOG(("nsHttpHandler::NotifyObservers [chan=%p event=\"%s\"]\n", chan, event));
841
0
    nsCOMPtr<nsIObserverService> obsService = services::GetObserverService();
842
0
    if (obsService)
843
0
        obsService->NotifyObservers(chan, event, nullptr);
844
0
}
845
846
nsresult
847
nsHttpHandler::AsyncOnChannelRedirect(nsIChannel* oldChan,
848
                                      nsIChannel* newChan,
849
                                      uint32_t flags,
850
                                      nsIEventTarget* mainThreadEventTarget)
851
0
{
852
0
  MOZ_ASSERT(NS_IsMainThread() && (oldChan && newChan));
853
0
854
0
  nsCOMPtr<nsIURI> newURI;
855
0
  newChan->GetURI(getter_AddRefs(newURI));
856
0
  MOZ_ASSERT(newURI);
857
0
858
0
  nsAutoCString scheme;
859
0
  newURI->GetScheme(scheme);
860
0
  MOZ_ASSERT(!scheme.IsEmpty());
861
0
862
0
  Telemetry::AccumulateCategoricalKeyed(
863
0
    scheme,
864
0
    oldChan->IsDocument()
865
0
      ? LABELS_NETWORK_HTTP_REDIRECT_TO_SCHEME::topLevel
866
0
      : LABELS_NETWORK_HTTP_REDIRECT_TO_SCHEME::subresource);
867
0
868
0
  // TODO E10S This helper has to be initialized on the other process
869
0
  RefPtr<nsAsyncRedirectVerifyHelper> redirectCallbackHelper =
870
0
    new nsAsyncRedirectVerifyHelper();
871
0
872
0
  return redirectCallbackHelper->Init(
873
0
    oldChan, newChan, flags, mainThreadEventTarget);
874
0
}
875
876
/* static */ nsresult
877
nsHttpHandler::GenerateHostPort(const nsCString& host, int32_t port,
878
                                nsACString& hostLine)
879
0
{
880
0
    return NS_GenerateHostPort(host, port, hostLine);
881
0
}
882
883
//-----------------------------------------------------------------------------
884
// nsHttpHandler <private>
885
//-----------------------------------------------------------------------------
886
887
const nsCString&
888
nsHttpHandler::UserAgent()
889
0
{
890
0
    if (nsContentUtils::ShouldResistFingerprinting() &&
891
0
        !mSpoofedUserAgent.IsEmpty()) {
892
0
        LOG(("using spoofed userAgent : %s\n", mSpoofedUserAgent.get()));
893
0
        return mSpoofedUserAgent;
894
0
    }
895
0
896
0
    if (!mUserAgentOverride.IsVoid()) {
897
0
        LOG(("using general.useragent.override : %s\n", mUserAgentOverride.get()));
898
0
        return mUserAgentOverride;
899
0
    }
900
0
901
0
    if (mUserAgentIsDirty) {
902
0
        BuildUserAgent();
903
0
        mUserAgentIsDirty = false;
904
0
    }
905
0
906
0
    return mUserAgent;
907
0
}
908
909
void
910
nsHttpHandler::BuildUserAgent()
911
0
{
912
0
    LOG(("nsHttpHandler::BuildUserAgent\n"));
913
0
914
0
    MOZ_ASSERT(!mLegacyAppName.IsEmpty() &&
915
0
               !mLegacyAppVersion.IsEmpty(),
916
0
               "HTTP cannot send practical requests without this much");
917
0
918
0
    // preallocate to worst-case size, which should always be better
919
0
    // than if we didn't preallocate at all.
920
0
    mUserAgent.SetCapacity(mLegacyAppName.Length() +
921
0
                           mLegacyAppVersion.Length() +
922
0
#ifndef UA_SPARE_PLATFORM
923
0
                           mPlatform.Length() +
924
0
#endif
925
0
                           mOscpu.Length() +
926
0
                           mMisc.Length() +
927
0
                           mProduct.Length() +
928
0
                           mProductSub.Length() +
929
0
                           mAppName.Length() +
930
0
                           mAppVersion.Length() +
931
0
                           mCompatFirefox.Length() +
932
0
                           mCompatDevice.Length() +
933
0
                           mDeviceModelId.Length() +
934
0
                           13);
935
0
936
0
    // Application portion
937
0
    mUserAgent.Assign(mLegacyAppName);
938
0
    mUserAgent += '/';
939
0
    mUserAgent += mLegacyAppVersion;
940
0
    mUserAgent += ' ';
941
0
942
0
    // Application comment
943
0
    mUserAgent += '(';
944
0
#ifndef UA_SPARE_PLATFORM
945
0
    if (!mPlatform.IsEmpty()) {
946
0
      mUserAgent += mPlatform;
947
0
      mUserAgent.AppendLiteral("; ");
948
0
    }
949
0
#endif
950
0
    if (!mCompatDevice.IsEmpty()) {
951
0
        mUserAgent += mCompatDevice;
952
0
        mUserAgent.AppendLiteral("; ");
953
0
    }
954
0
    else if (!mOscpu.IsEmpty()) {
955
0
      mUserAgent += mOscpu;
956
0
      mUserAgent.AppendLiteral("; ");
957
0
    }
958
0
    if (!mDeviceModelId.IsEmpty()) {
959
0
        mUserAgent += mDeviceModelId;
960
0
        mUserAgent.AppendLiteral("; ");
961
0
    }
962
0
    mUserAgent += mMisc;
963
0
    mUserAgent += ')';
964
0
965
0
    // Product portion
966
0
    mUserAgent += ' ';
967
0
    mUserAgent += mProduct;
968
0
    mUserAgent += '/';
969
0
    mUserAgent += mProductSub;
970
0
971
0
    bool isFirefox = mAppName.EqualsLiteral("Firefox");
972
0
    if (isFirefox || mCompatFirefoxEnabled) {
973
0
        // "Firefox/x.y" (compatibility) app token
974
0
        mUserAgent += ' ';
975
0
        mUserAgent += mCompatFirefox;
976
0
    }
977
0
    if (!isFirefox) {
978
0
        // App portion
979
0
        mUserAgent += ' ';
980
0
        mUserAgent += mAppName;
981
0
        mUserAgent += '/';
982
0
        mUserAgent += mAppVersion;
983
0
    }
984
0
}
985
986
#ifdef XP_WIN
987
#define WNT_BASE "Windows NT %ld.%ld"
988
#define W64_PREFIX "; Win64"
989
#endif
990
991
void
992
nsHttpHandler::InitUserAgentComponents()
993
1
{
994
1
#ifndef MOZ_UA_OS_AGNOSTIC
995
1
    // Gather platform.
996
1
    mPlatform.AssignLiteral(
997
#if defined(ANDROID)
998
    "Android"
999
#elif defined(XP_WIN)
1000
    "Windows"
1001
#elif defined(XP_MACOSX)
1002
    "Macintosh"
1003
#elif defined(XP_UNIX)
1004
    // We historically have always had X11 here,
1005
1
    // and there seems little a webpage can sensibly do
1006
1
    // based on it being something else, so use X11 for
1007
1
    // backwards compatibility in all cases.
1008
1
    "X11"
1009
1
#endif
1010
1
    );
1011
1
#endif
1012
1
1013
1
1014
#ifdef ANDROID
1015
    nsCOMPtr<nsIPropertyBag2> infoService = do_GetService("@mozilla.org/system-info;1");
1016
    MOZ_ASSERT(infoService, "Could not find a system info service");
1017
    nsresult rv;
1018
    // Add the Android version number to the Fennec platform identifier.
1019
#if defined MOZ_WIDGET_ANDROID
1020
#ifndef MOZ_UA_OS_AGNOSTIC // Don't add anything to mPlatform since it's empty.
1021
    nsAutoString androidVersion;
1022
    rv = infoService->GetPropertyAsAString(
1023
        NS_LITERAL_STRING("release_version"), androidVersion);
1024
    if (NS_SUCCEEDED(rv)) {
1025
      mPlatform += " ";
1026
      // If the 2nd character is a ".", we know the major version is a single
1027
      // digit. If we're running on a version below 4 we pretend to be on
1028
      // Android KitKat (4.4) to work around scripts sniffing for low versions.
1029
      if (androidVersion[1] == 46 && androidVersion[0] < 52) {
1030
        mPlatform += "4.4";
1031
      } else {
1032
        mPlatform += NS_LossyConvertUTF16toASCII(androidVersion);
1033
      }
1034
    }
1035
#endif
1036
#endif
1037
    // Add the `Mobile` or `Tablet` or `TV` token when running on device.
1038
    bool isTablet;
1039
    rv = infoService->GetPropertyAsBool(NS_LITERAL_STRING("tablet"), &isTablet);
1040
    if (NS_SUCCEEDED(rv) && isTablet) {
1041
        mCompatDevice.AssignLiteral("Tablet");
1042
    } else {
1043
        bool isTV;
1044
        rv = infoService->GetPropertyAsBool(NS_LITERAL_STRING("tv"), &isTV);
1045
        if (NS_SUCCEEDED(rv) && isTV) {
1046
            mCompatDevice.AssignLiteral("TV");
1047
        } else {
1048
            mCompatDevice.AssignLiteral("Mobile");
1049
        }
1050
    }
1051
1052
    if (Preferences::GetBool(UA_PREF("use_device"), false)) {
1053
        mDeviceModelId = mozilla::net::GetDeviceModelId();
1054
    }
1055
#endif // ANDROID
1056
1057
1
#ifndef MOZ_UA_OS_AGNOSTIC
1058
1
    // Gather OS/CPU.
1059
#if defined(XP_WIN)
1060
    OSVERSIONINFO info = { sizeof(OSVERSIONINFO) };
1061
#pragma warning(push)
1062
#pragma warning(disable:4996)
1063
    if (GetVersionEx(&info)) {
1064
#pragma warning(pop)
1065
        const char *format;
1066
#if defined _M_IA64
1067
        format = WNT_BASE W64_PREFIX "; IA64";
1068
#elif defined _M_X64 || defined _M_AMD64
1069
        format = WNT_BASE W64_PREFIX "; x64";
1070
#else
1071
        BOOL isWow64 = FALSE;
1072
        if (!IsWow64Process(GetCurrentProcess(), &isWow64)) {
1073
            isWow64 = FALSE;
1074
        }
1075
        format = isWow64
1076
          ? WNT_BASE "; WOW64"
1077
          : WNT_BASE;
1078
#endif
1079
        SmprintfPointer buf = mozilla::Smprintf(format,
1080
                                                info.dwMajorVersion,
1081
                                                info.dwMinorVersion);
1082
        if (buf) {
1083
            mOscpu = buf.get();
1084
        }
1085
    }
1086
#elif defined (XP_MACOSX)
1087
#if defined(__ppc__)
1088
    mOscpu.AssignLiteral("PPC Mac OS X");
1089
#elif defined(__i386__) || defined(__x86_64__)
1090
    mOscpu.AssignLiteral("Intel Mac OS X");
1091
#endif
1092
    SInt32 majorVersion = nsCocoaFeatures::OSXVersionMajor();
1093
    SInt32 minorVersion = nsCocoaFeatures::OSXVersionMinor();
1094
    mOscpu += nsPrintfCString(" %d.%d", static_cast<int>(majorVersion),
1095
                              static_cast<int>(minorVersion));
1096
#elif defined (XP_UNIX)
1097
    struct utsname name;
1098
1
1099
1
    int ret = uname(&name);
1100
1
    if (ret >= 0) {
1101
1
        nsAutoCString buf;
1102
1
        buf =  (char*)name.sysname;
1103
1
1104
1
        if (strcmp(name.machine, "x86_64") == 0 &&
1105
1
            sizeof(void *) == sizeof(int32_t)) {
1106
0
            // We're running 32-bit code on x86_64. Make this browser
1107
0
            // look like it's running on i686 hardware, but append "
1108
0
            // (x86_64)" to the end of the oscpu identifier to be able
1109
0
            // to differentiate this from someone running 64-bit code
1110
0
            // on x86_64..
1111
0
1112
0
            buf += " i686 on x86_64";
1113
1
        } else {
1114
1
            buf += ' ';
1115
1
1116
#ifdef AIX
1117
            // AIX uname returns machine specific info in the uname.machine
1118
            // field and does not return the cpu type like other platforms.
1119
            // We use the AIX version and release numbers instead.
1120
            buf += (char*)name.version;
1121
            buf += '.';
1122
            buf += (char*)name.release;
1123
#else
1124
            buf += (char*)name.machine;
1125
1
#endif
1126
1
        }
1127
1
1128
1
        mOscpu.Assign(buf);
1129
1
    }
1130
1
#endif
1131
1
#endif
1132
1
1133
1
    mUserAgentIsDirty = true;
1134
1
}
1135
1136
uint32_t
1137
nsHttpHandler::MaxSocketCount()
1138
1
{
1139
1
    PR_CallOnce(&nsSocketTransportService::gMaxCountInitOnce,
1140
1
                nsSocketTransportService::DiscoverMaxCount);
1141
1
    // Don't use the full max count because sockets can be held in
1142
1
    // the persistent connection pool for a long time and that could
1143
1
    // starve other users.
1144
1
1145
1
    uint32_t maxCount = nsSocketTransportService::gMaxCount;
1146
1
    if (maxCount <= 8)
1147
0
        maxCount = 1;
1148
1
    else
1149
1
        maxCount -= 8;
1150
1
1151
1
    return maxCount;
1152
1
}
1153
1154
void
1155
nsHttpHandler::PrefsChanged(const char *pref)
1156
1
{
1157
1
    nsresult rv = NS_OK;
1158
1
    int32_t val;
1159
1
1160
1
    LOG(("nsHttpHandler::PrefsChanged [pref=%s]\n", pref));
1161
1
1162
95
#define PREF_CHANGED(p) ((pref == nullptr) || !PL_strcmp(pref, p))
1163
1
#define MULTI_PREF_CHANGED(p) \
1164
1
  ((pref == nullptr) || !PL_strncmp(pref, p, sizeof(p) - 1))
1165
1
1166
1
    // If a security pref changed, lets clear our connection pool reuse
1167
1
    if (MULTI_PREF_CHANGED(SECURITY_PREFIX)) {
1168
1
        LOG(("nsHttpHandler::PrefsChanged Security Pref Changed %s\n", pref));
1169
1
        if (mConnMgr) {
1170
0
            rv = mConnMgr->DoShiftReloadConnectionCleanup(nullptr);
1171
0
            if (NS_FAILED(rv)) {
1172
0
                LOG(("nsHttpHandler::PrefsChanged "
1173
0
                     "DoShiftReloadConnectionCleanup failed (%08x)\n", static_cast<uint32_t>(rv)));
1174
0
            }
1175
0
            rv = mConnMgr->PruneDeadConnections();
1176
0
            if (NS_FAILED(rv)) {
1177
0
                LOG(("nsHttpHandler::PrefsChanged "
1178
0
                     "PruneDeadConnections failed (%08x)\n", static_cast<uint32_t>(rv)));
1179
0
            }
1180
0
        }
1181
1
    }
1182
1
1183
1
    //
1184
1
    // UA components
1185
1
    //
1186
1
1187
1
    bool cVar = false;
1188
1
1189
1
    if (PREF_CHANGED(UA_PREF("compatMode.firefox"))) {
1190
1
        rv = Preferences::GetBool(UA_PREF("compatMode.firefox"), &cVar);
1191
1
        mCompatFirefoxEnabled = (NS_SUCCEEDED(rv) && cVar);
1192
1
        mUserAgentIsDirty = true;
1193
1
    }
1194
1
1195
1
    // general.useragent.override
1196
1
    if (PREF_CHANGED(UA_PREF("override"))) {
1197
1
        Preferences::GetCString(UA_PREF("override"), mUserAgentOverride);
1198
1
        mUserAgentIsDirty = true;
1199
1
    }
1200
1
1201
#ifdef ANDROID
1202
    // general.useragent.use_device
1203
    if (PREF_CHANGED(UA_PREF("use_device"))) {
1204
        if (Preferences::GetBool(UA_PREF("use_device"), false)) {
1205
            mDeviceModelId = mozilla::net::GetDeviceModelId();
1206
        } else {
1207
            mDeviceModelId = EmptyCString();
1208
        }
1209
        mUserAgentIsDirty = true;
1210
    }
1211
#endif
1212
1213
1
    //
1214
1
    // HTTP options
1215
1
    //
1216
1
1217
1
    if (PREF_CHANGED(HTTP_PREF("keep-alive.timeout"))) {
1218
1
        rv = Preferences::GetInt(HTTP_PREF("keep-alive.timeout"), &val);
1219
1
        if (NS_SUCCEEDED(rv))
1220
1
            mIdleTimeout = PR_SecondsToInterval(clamped(val, 1, 0xffff));
1221
1
    }
1222
1
1223
1
    if (PREF_CHANGED(HTTP_PREF("request.max-attempts"))) {
1224
1
        rv = Preferences::GetInt(HTTP_PREF("request.max-attempts"), &val);
1225
1
        if (NS_SUCCEEDED(rv))
1226
1
            mMaxRequestAttempts = (uint16_t) clamped(val, 1, 0xffff);
1227
1
    }
1228
1
1229
1
    if (PREF_CHANGED(HTTP_PREF("request.max-start-delay"))) {
1230
1
        rv = Preferences::GetInt(HTTP_PREF("request.max-start-delay"), &val);
1231
1
        if (NS_SUCCEEDED(rv)) {
1232
1
            mMaxRequestDelay = (uint16_t) clamped(val, 0, 0xffff);
1233
1
            if (mConnMgr) {
1234
0
                rv = mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_REQUEST_DELAY,
1235
0
                                           mMaxRequestDelay);
1236
0
                if (NS_FAILED(rv)) {
1237
0
                    LOG(("nsHttpHandler::PrefsChanged (request.max-start-delay)"
1238
0
                         "UpdateParam failed (%08x)\n", static_cast<uint32_t>(rv)));
1239
0
                }
1240
0
            }
1241
1
        }
1242
1
    }
1243
1
1244
1
    if (PREF_CHANGED(HTTP_PREF("response.timeout"))) {
1245
1
        rv = Preferences::GetInt(HTTP_PREF("response.timeout"), &val);
1246
1
        if (NS_SUCCEEDED(rv))
1247
1
            mResponseTimeout = PR_SecondsToInterval(clamped(val, 0, 0xffff));
1248
1
    }
1249
1
1250
1
    if (PREF_CHANGED(HTTP_PREF("network-changed.timeout"))) {
1251
1
        rv = Preferences::GetInt(HTTP_PREF("network-changed.timeout"), &val);
1252
1
        if (NS_SUCCEEDED(rv))
1253
1
            mNetworkChangedTimeout = clamped(val, 1, 600) * 1000;
1254
1
    }
1255
1
1256
1
    if (PREF_CHANGED(HTTP_PREF("max-connections"))) {
1257
1
        rv = Preferences::GetInt(HTTP_PREF("max-connections"), &val);
1258
1
        if (NS_SUCCEEDED(rv)) {
1259
1
1260
1
            mMaxConnections = (uint16_t) clamped((uint32_t)val,
1261
1
                                                 (uint32_t)1, MaxSocketCount());
1262
1
1263
1
            if (mConnMgr) {
1264
0
                rv = mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_CONNECTIONS,
1265
0
                                           mMaxConnections);
1266
0
                if (NS_FAILED(rv)) {
1267
0
                    LOG(("nsHttpHandler::PrefsChanged (max-connections)"
1268
0
                         "UpdateParam failed (%08x)\n", static_cast<uint32_t>(rv)));
1269
0
                }
1270
0
            }
1271
1
        }
1272
1
    }
1273
1
1274
1
    if (PREF_CHANGED(HTTP_PREF("max-urgent-start-excessive-connections-per-host"))) {
1275
1
        rv = Preferences::GetInt(HTTP_PREF("max-urgent-start-excessive-connections-per-host"), &val);
1276
1
        if (NS_SUCCEEDED(rv)) {
1277
1
            mMaxUrgentExcessiveConns = (uint8_t) clamped(val, 1, 0xff);
1278
1
            if (mConnMgr) {
1279
0
                rv = mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_URGENT_START_Q,
1280
0
                                           mMaxUrgentExcessiveConns);
1281
0
                if (NS_FAILED(rv)) {
1282
0
                    LOG(("nsHttpHandler::PrefsChanged (max-urgent-start-excessive-connections-per-host)"
1283
0
                         "UpdateParam failed (%08x)\n", static_cast<uint32_t>(rv)));
1284
0
                }
1285
0
             }
1286
1
          }
1287
1
    }
1288
1
1289
1
    if (PREF_CHANGED(HTTP_PREF("max-persistent-connections-per-server"))) {
1290
1
        rv = Preferences::GetInt(HTTP_PREF("max-persistent-connections-per-server"), &val);
1291
1
        if (NS_SUCCEEDED(rv)) {
1292
1
            mMaxPersistentConnectionsPerServer = (uint8_t) clamped(val, 1, 0xff);
1293
1
            if (mConnMgr) {
1294
0
                rv = mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_PERSISTENT_CONNECTIONS_PER_HOST,
1295
0
                                           mMaxPersistentConnectionsPerServer);
1296
0
                if (NS_FAILED(rv)) {
1297
0
                    LOG(("nsHttpHandler::PrefsChanged (max-persistent-connections-per-server)"
1298
0
                         "UpdateParam failed (%08x)\n", static_cast<uint32_t>(rv)));
1299
0
                }
1300
0
            }
1301
1
        }
1302
1
    }
1303
1
1304
1
    if (PREF_CHANGED(HTTP_PREF("max-persistent-connections-per-proxy"))) {
1305
1
        rv = Preferences::GetInt(HTTP_PREF("max-persistent-connections-per-proxy"), &val);
1306
1
        if (NS_SUCCEEDED(rv)) {
1307
1
            mMaxPersistentConnectionsPerProxy = (uint8_t) clamped(val, 1, 0xff);
1308
1
            if (mConnMgr) {
1309
0
                rv = mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_PERSISTENT_CONNECTIONS_PER_PROXY,
1310
0
                                           mMaxPersistentConnectionsPerProxy);
1311
0
                if (NS_FAILED(rv)) {
1312
0
                    LOG(("nsHttpHandler::PrefsChanged (max-persistent-connections-per-proxy)"
1313
0
                         "UpdateParam failed (%08x)\n", static_cast<uint32_t>(rv)));
1314
0
                }
1315
0
            }
1316
1
        }
1317
1
    }
1318
1
1319
1
    if (PREF_CHANGED(HTTP_PREF("sendRefererHeader"))) {
1320
1
        rv = Preferences::GetInt(HTTP_PREF("sendRefererHeader"), &val);
1321
1
        if (NS_SUCCEEDED(rv))
1322
1
            mReferrerLevel = (uint8_t) clamped(val, 0, 0xff);
1323
1
    }
1324
1
1325
1
    if (PREF_CHANGED(HTTP_PREF("referer.spoofSource"))) {
1326
1
        rv = Preferences::GetBool(HTTP_PREF("referer.spoofSource"), &cVar);
1327
1
        if (NS_SUCCEEDED(rv))
1328
1
            mSpoofReferrerSource = cVar;
1329
1
    }
1330
1
1331
1
    if (PREF_CHANGED(HTTP_PREF("referer.hideOnionSource"))) {
1332
1
        rv = Preferences::GetBool(HTTP_PREF("referer.hideOnionSource"), &cVar);
1333
1
        if (NS_SUCCEEDED(rv))
1334
1
            mHideOnionReferrerSource = cVar;
1335
1
    }
1336
1
1337
1
    if (PREF_CHANGED(HTTP_PREF("referer.trimmingPolicy"))) {
1338
1
        rv = Preferences::GetInt(HTTP_PREF("referer.trimmingPolicy"), &val);
1339
1
        if (NS_SUCCEEDED(rv))
1340
1
            mReferrerTrimmingPolicy = (uint8_t) clamped(val, 0, 2);
1341
1
    }
1342
1
1343
1
    if (PREF_CHANGED(HTTP_PREF("referer.XOriginTrimmingPolicy"))) {
1344
1
        rv = Preferences::GetInt(HTTP_PREF("referer.XOriginTrimmingPolicy"), &val);
1345
1
        if (NS_SUCCEEDED(rv))
1346
1
            mReferrerXOriginTrimmingPolicy = (uint8_t) clamped(val, 0, 2);
1347
1
    }
1348
1
1349
1
    if (PREF_CHANGED(HTTP_PREF("referer.XOriginPolicy"))) {
1350
1
        rv = Preferences::GetInt(HTTP_PREF("referer.XOriginPolicy"), &val);
1351
1
        if (NS_SUCCEEDED(rv))
1352
1
            mReferrerXOriginPolicy = (uint8_t) clamped(val, 0, 0xff);
1353
1
    }
1354
1
1355
1
    if (PREF_CHANGED(HTTP_PREF("redirection-limit"))) {
1356
1
        rv = Preferences::GetInt(HTTP_PREF("redirection-limit"), &val);
1357
1
        if (NS_SUCCEEDED(rv))
1358
1
            mRedirectionLimit = (uint8_t) clamped(val, 0, 0xff);
1359
1
    }
1360
1
1361
1
    if (PREF_CHANGED(HTTP_PREF("connection-retry-timeout"))) {
1362
1
        rv = Preferences::GetInt(HTTP_PREF("connection-retry-timeout"), &val);
1363
1
        if (NS_SUCCEEDED(rv))
1364
1
            mIdleSynTimeout = (uint16_t) clamped(val, 0, 3000);
1365
1
    }
1366
1
1367
1
    if (PREF_CHANGED(HTTP_PREF("fast-fallback-to-IPv4"))) {
1368
1
        rv = Preferences::GetBool(HTTP_PREF("fast-fallback-to-IPv4"), &cVar);
1369
1
        if (NS_SUCCEEDED(rv))
1370
1
            mFastFallbackToIPv4 = cVar;
1371
1
    }
1372
1
1373
1
    if (PREF_CHANGED(HTTP_PREF("fallback-connection-timeout"))) {
1374
1
        rv = Preferences::GetInt(HTTP_PREF("fallback-connection-timeout"), &val);
1375
1
        if (NS_SUCCEEDED(rv))
1376
1
            mFallbackSynTimeout = (uint16_t) clamped(val, 0, 10 * 60);
1377
1
    }
1378
1
1379
1
    if (PREF_CHANGED(HTTP_PREF("version"))) {
1380
1
        nsAutoCString httpVersion;
1381
1
        Preferences::GetCString(HTTP_PREF("version"), httpVersion);
1382
1
        if (!httpVersion.IsVoid()) {
1383
1
            if (httpVersion.EqualsLiteral("1.1"))
1384
1
                mHttpVersion = HttpVersion::v1_1;
1385
0
            else if (httpVersion.EqualsLiteral("0.9"))
1386
0
                mHttpVersion = HttpVersion::v0_9;
1387
0
            else
1388
0
                mHttpVersion = HttpVersion::v1_0;
1389
1
        }
1390
1
    }
1391
1
1392
1
    if (PREF_CHANGED(HTTP_PREF("proxy.version"))) {
1393
1
        nsAutoCString httpVersion;
1394
1
        Preferences::GetCString(HTTP_PREF("proxy.version"), httpVersion);
1395
1
        if (!httpVersion.IsVoid()) {
1396
1
            if (httpVersion.EqualsLiteral("1.1"))
1397
1
                mProxyHttpVersion = HttpVersion::v1_1;
1398
0
            else
1399
0
                mProxyHttpVersion = HttpVersion::v1_0;
1400
1
            // it does not make sense to issue a HTTP/0.9 request to a proxy server
1401
1
        }
1402
1
    }
1403
1
1404
1
    if (PREF_CHANGED(HTTP_PREF("qos"))) {
1405
1
        rv = Preferences::GetInt(HTTP_PREF("qos"), &val);
1406
1
        if (NS_SUCCEEDED(rv))
1407
1
            mQoSBits = (uint8_t) clamped(val, 0, 0xff);
1408
1
    }
1409
1
1410
1
    if (PREF_CHANGED(HTTP_PREF("accept.default"))) {
1411
1
        nsAutoCString accept;
1412
1
        rv = Preferences::GetCString(HTTP_PREF("accept.default"), accept);
1413
1
        if (NS_SUCCEEDED(rv)) {
1414
1
            rv = SetAccept(accept.get());
1415
1
            MOZ_ASSERT(NS_SUCCEEDED(rv));
1416
1
        }
1417
1
    }
1418
1
1419
1
    if (PREF_CHANGED(HTTP_PREF("accept-encoding"))) {
1420
1
        nsAutoCString acceptEncodings;
1421
1
        rv = Preferences::GetCString(HTTP_PREF("accept-encoding"), acceptEncodings);
1422
1
        if (NS_SUCCEEDED(rv)) {
1423
1
            rv = SetAcceptEncodings(acceptEncodings.get(), false);
1424
1
            MOZ_ASSERT(NS_SUCCEEDED(rv));
1425
1
        }
1426
1
    }
1427
1
1428
1
    if (PREF_CHANGED(HTTP_PREF("accept-encoding.secure"))) {
1429
1
        nsAutoCString acceptEncodings;
1430
1
        rv = Preferences::GetCString(HTTP_PREF("accept-encoding.secure"),
1431
1
                                acceptEncodings);
1432
1
        if (NS_SUCCEEDED(rv)) {
1433
1
            rv = SetAcceptEncodings(acceptEncodings.get(), true);
1434
1
            MOZ_ASSERT(NS_SUCCEEDED(rv));
1435
1
        }
1436
1
    }
1437
1
1438
1
    if (PREF_CHANGED(HTTP_PREF("default-socket-type"))) {
1439
1
        nsAutoCString sval;
1440
1
        rv = Preferences::GetCString(HTTP_PREF("default-socket-type"), sval);
1441
1
        if (NS_SUCCEEDED(rv)) {
1442
1
            if (sval.IsEmpty())
1443
1
                mDefaultSocketType.SetIsVoid(true);
1444
0
            else {
1445
0
                // verify that this socket type is actually valid
1446
0
                nsCOMPtr<nsISocketProviderService> sps(
1447
0
                        do_GetService(NS_SOCKETPROVIDERSERVICE_CONTRACTID));
1448
0
                if (sps) {
1449
0
                    nsCOMPtr<nsISocketProvider> sp;
1450
0
                    rv = sps->GetSocketProvider(sval.get(), getter_AddRefs(sp));
1451
0
                    if (NS_SUCCEEDED(rv)) {
1452
0
                        // OK, this looks like a valid socket provider.
1453
0
                        mDefaultSocketType.Assign(sval);
1454
0
                    }
1455
0
                }
1456
0
            }
1457
1
        }
1458
1
    }
1459
1
1460
1
    if (PREF_CHANGED(HTTP_PREF("prompt-temp-redirect"))) {
1461
1
        rv = Preferences::GetBool(HTTP_PREF("prompt-temp-redirect"), &cVar);
1462
1
        if (NS_SUCCEEDED(rv)) {
1463
1
            mPromptTempRedirect = cVar;
1464
1
        }
1465
1
    }
1466
1
1467
1
    if (PREF_CHANGED(HTTP_PREF("assoc-req.enforce"))) {
1468
1
        cVar = false;
1469
1
        rv = Preferences::GetBool(HTTP_PREF("assoc-req.enforce"), &cVar);
1470
1
        if (NS_SUCCEEDED(rv))
1471
1
            mEnforceAssocReq = cVar;
1472
1
    }
1473
1
1474
1
    // enable Persistent caching for HTTPS - bug#205921
1475
1
    if (PREF_CHANGED(BROWSER_PREF("disk_cache_ssl"))) {
1476
1
        cVar = false;
1477
1
        rv = Preferences::GetBool(BROWSER_PREF("disk_cache_ssl"), &cVar);
1478
1
        if (NS_SUCCEEDED(rv))
1479
1
            mEnablePersistentHttpsCaching = cVar;
1480
1
    }
1481
1
1482
1
    if (PREF_CHANGED(HTTP_PREF("phishy-userpass-length"))) {
1483
1
        rv = Preferences::GetInt(HTTP_PREF("phishy-userpass-length"), &val);
1484
1
        if (NS_SUCCEEDED(rv))
1485
1
            mPhishyUserPassLength = (uint8_t) clamped(val, 0, 0xff);
1486
1
    }
1487
1
1488
1
    if (PREF_CHANGED(HTTP_PREF("spdy.enabled"))) {
1489
1
        rv = Preferences::GetBool(HTTP_PREF("spdy.enabled"), &cVar);
1490
1
        if (NS_SUCCEEDED(rv))
1491
1
            mEnableSpdy = cVar;
1492
1
    }
1493
1
1494
1
    if (PREF_CHANGED(HTTP_PREF("spdy.enabled.http2"))) {
1495
1
        rv = Preferences::GetBool(HTTP_PREF("spdy.enabled.http2"), &cVar);
1496
1
        if (NS_SUCCEEDED(rv))
1497
1
            mHttp2Enabled = cVar;
1498
1
    }
1499
1
1500
1
    if (PREF_CHANGED(HTTP_PREF("spdy.enabled.deps"))) {
1501
1
        rv = Preferences::GetBool(HTTP_PREF("spdy.enabled.deps"), &cVar);
1502
1
        if (NS_SUCCEEDED(rv))
1503
1
            mUseH2Deps = cVar;
1504
1
    }
1505
1
1506
1
    if (PREF_CHANGED(HTTP_PREF("spdy.enforce-tls-profile"))) {
1507
1
        rv = Preferences::GetBool(HTTP_PREF("spdy.enforce-tls-profile"), &cVar);
1508
1
        if (NS_SUCCEEDED(rv))
1509
1
            mEnforceHttp2TlsProfile = cVar;
1510
1
    }
1511
1
1512
1
    if (PREF_CHANGED(HTTP_PREF("spdy.coalesce-hostnames"))) {
1513
1
        rv = Preferences::GetBool(HTTP_PREF("spdy.coalesce-hostnames"), &cVar);
1514
1
        if (NS_SUCCEEDED(rv))
1515
1
            mCoalesceSpdy = cVar;
1516
1
    }
1517
1
1518
1
    if (PREF_CHANGED(HTTP_PREF("spdy.persistent-settings"))) {
1519
1
        rv = Preferences::GetBool(HTTP_PREF("spdy.persistent-settings"),
1520
1
                                &cVar);
1521
1
        if (NS_SUCCEEDED(rv))
1522
1
            mSpdyPersistentSettings = cVar;
1523
1
    }
1524
1
1525
1
    if (PREF_CHANGED(HTTP_PREF("spdy.timeout"))) {
1526
1
        rv = Preferences::GetInt(HTTP_PREF("spdy.timeout"), &val);
1527
1
        if (NS_SUCCEEDED(rv))
1528
1
            mSpdyTimeout = PR_SecondsToInterval(clamped(val, 1, 0xffff));
1529
1
    }
1530
1
1531
1
    if (PREF_CHANGED(HTTP_PREF("spdy.chunk-size"))) {
1532
1
        // keep this within http/2 ranges of 1 to 2^14-1
1533
1
        rv = Preferences::GetInt(HTTP_PREF("spdy.chunk-size"), &val);
1534
1
        if (NS_SUCCEEDED(rv))
1535
1
            mSpdySendingChunkSize = (uint32_t) clamped(val, 1, 0x3fff);
1536
1
    }
1537
1
1538
1
    // The amount of idle seconds on a spdy connection before initiating a
1539
1
    // server ping. 0 will disable.
1540
1
    if (PREF_CHANGED(HTTP_PREF("spdy.ping-threshold"))) {
1541
1
        rv = Preferences::GetInt(HTTP_PREF("spdy.ping-threshold"), &val);
1542
1
        if (NS_SUCCEEDED(rv))
1543
1
            mSpdyPingThreshold =
1544
1
                PR_SecondsToInterval((uint16_t) clamped(val, 0, 0x7fffffff));
1545
1
    }
1546
1
1547
1
    // The amount of seconds to wait for a spdy ping response before
1548
1
    // closing the session.
1549
1
    if (PREF_CHANGED(HTTP_PREF("spdy.ping-timeout"))) {
1550
1
        rv = Preferences::GetInt(HTTP_PREF("spdy.ping-timeout"), &val);
1551
1
        if (NS_SUCCEEDED(rv))
1552
1
            mSpdyPingTimeout =
1553
1
                PR_SecondsToInterval((uint16_t) clamped(val, 0, 0x7fffffff));
1554
1
    }
1555
1
1556
1
    if (PREF_CHANGED(HTTP_PREF("spdy.allow-push"))) {
1557
1
        rv = Preferences::GetBool(HTTP_PREF("spdy.allow-push"),
1558
1
                                &cVar);
1559
1
        if (NS_SUCCEEDED(rv))
1560
1
            mAllowPush = cVar;
1561
1
    }
1562
1
1563
1
    if (PREF_CHANGED(HTTP_PREF("altsvc.enabled"))) {
1564
1
        rv = Preferences::GetBool(HTTP_PREF("altsvc.enabled"),
1565
1
                                &cVar);
1566
1
        if (NS_SUCCEEDED(rv))
1567
1
            mEnableAltSvc = cVar;
1568
1
    }
1569
1
1570
1
1571
1
    if (PREF_CHANGED(HTTP_PREF("altsvc.oe"))) {
1572
1
        rv = Preferences::GetBool(HTTP_PREF("altsvc.oe"),
1573
1
                                &cVar);
1574
1
        if (NS_SUCCEEDED(rv))
1575
1
            mEnableAltSvcOE = cVar;
1576
1
    }
1577
1
1578
1
    if (PREF_CHANGED(HTTP_PREF("originextension"))) {
1579
1
        rv = Preferences::GetBool(HTTP_PREF("originextension"),
1580
1
                                &cVar);
1581
1
        if (NS_SUCCEEDED(rv))
1582
1
            mEnableOriginExtension = cVar;
1583
1
    }
1584
1
1585
1
    if (PREF_CHANGED(HTTP_PREF("spdy.push-allowance"))) {
1586
1
        rv = Preferences::GetInt(HTTP_PREF("spdy.push-allowance"), &val);
1587
1
        if (NS_SUCCEEDED(rv)) {
1588
1
            mSpdyPushAllowance =
1589
1
                static_cast<uint32_t>
1590
1
                (clamped(val, 1024, static_cast<int32_t>(ASpdySession::kInitialRwin)));
1591
1
        }
1592
1
    }
1593
1
1594
1
    if (PREF_CHANGED(HTTP_PREF("spdy.pull-allowance"))) {
1595
1
        rv = Preferences::GetInt(HTTP_PREF("spdy.pull-allowance"), &val);
1596
1
        if (NS_SUCCEEDED(rv)) {
1597
1
            mSpdyPullAllowance =
1598
1
                static_cast<uint32_t>(clamped(val, 1024, 0x7fffffff));
1599
1
        }
1600
1
    }
1601
1
1602
1
    if (PREF_CHANGED(HTTP_PREF("spdy.default-concurrent"))) {
1603
1
        rv = Preferences::GetInt(HTTP_PREF("spdy.default-concurrent"), &val);
1604
1
        if (NS_SUCCEEDED(rv)) {
1605
1
            mDefaultSpdyConcurrent =
1606
1
                static_cast<uint32_t>(std::max<int32_t>(std::min<int32_t>(val, 9999), 1));
1607
1
        }
1608
1
    }
1609
1
1610
1
    // The amount of seconds to wait for a spdy ping response before
1611
1
    // closing the session.
1612
1
    if (PREF_CHANGED(HTTP_PREF("spdy.send-buffer-size"))) {
1613
1
        rv = Preferences::GetInt(HTTP_PREF("spdy.send-buffer-size"), &val);
1614
1
        if (NS_SUCCEEDED(rv))
1615
1
            mSpdySendBufferSize = (uint32_t) clamped(val, 1500, 0x7fffffff);
1616
1
    }
1617
1
1618
1
    // The maximum amount of time to wait for socket transport to be
1619
1
    // established
1620
1
    if (PREF_CHANGED(HTTP_PREF("connection-timeout"))) {
1621
1
        rv = Preferences::GetInt(HTTP_PREF("connection-timeout"), &val);
1622
1
        if (NS_SUCCEEDED(rv))
1623
1
            // the pref is in seconds, but the variable is in milliseconds
1624
1
            mConnectTimeout = clamped(val, 1, 0xffff) * PR_MSEC_PER_SEC;
1625
1
    }
1626
1
1627
1
    // The maximum amount of time to wait for a tls handshake to finish.
1628
1
    if (PREF_CHANGED(HTTP_PREF("tls-handshake-timeout"))) {
1629
1
        rv = Preferences::GetInt(HTTP_PREF("tls-handshake-timeout"), &val);
1630
1
        if (NS_SUCCEEDED(rv))
1631
1
            // the pref is in seconds, but the variable is in milliseconds
1632
1
            mTLSHandshakeTimeout = clamped(val, 1, 0xffff) * PR_MSEC_PER_SEC;
1633
1
    }
1634
1
1635
1
    // The maximum number of current global half open sockets allowable
1636
1
    // for starting a new speculative connection.
1637
1
    if (PREF_CHANGED(HTTP_PREF("speculative-parallel-limit"))) {
1638
1
        rv = Preferences::GetInt(HTTP_PREF("speculative-parallel-limit"), &val);
1639
1
        if (NS_SUCCEEDED(rv))
1640
1
            mParallelSpeculativeConnectLimit = (uint32_t) clamped(val, 0, 1024);
1641
1
    }
1642
1
1643
1
    // Whether or not to block requests for non head js/css items (e.g. media)
1644
1
    // while those elements load.
1645
1
    if (PREF_CHANGED(HTTP_PREF("rendering-critical-requests-prioritization"))) {
1646
1
        rv = Preferences::GetBool(HTTP_PREF("rendering-critical-requests-prioritization"), &cVar);
1647
1
        if (NS_SUCCEEDED(rv))
1648
1
            mCriticalRequestPrioritization = cVar;
1649
1
    }
1650
1
1651
1
    // on transition of network.http.diagnostics to true print
1652
1
    // a bunch of information to the console
1653
1
    if (pref && PREF_CHANGED(HTTP_PREF("diagnostics"))) {
1654
0
        rv = Preferences::GetBool(HTTP_PREF("diagnostics"), &cVar);
1655
0
        if (NS_SUCCEEDED(rv) && cVar) {
1656
0
            if (mConnMgr)
1657
0
                mConnMgr->PrintDiagnostics();
1658
0
        }
1659
0
    }
1660
1
1661
1
    if (PREF_CHANGED(HTTP_PREF("max_response_header_size"))) {
1662
1
        rv = Preferences::GetInt(HTTP_PREF("max_response_header_size"), &val);
1663
1
        if (NS_SUCCEEDED(rv)) {
1664
1
            mMaxHttpResponseHeaderSize = val;
1665
1
        }
1666
1
    }
1667
1
1668
1
    if (PREF_CHANGED(HTTP_PREF("throttle.enable"))) {
1669
1
        rv = Preferences::GetBool(HTTP_PREF("throttle.enable"), &mThrottleEnabled);
1670
1
        if (NS_SUCCEEDED(rv) && mConnMgr) {
1671
0
            Unused << mConnMgr->UpdateParam(nsHttpConnectionMgr::THROTTLING_ENABLED,
1672
0
                                            static_cast<int32_t>(mThrottleEnabled));
1673
0
        }
1674
1
    }
1675
1
1676
1
    if (PREF_CHANGED(HTTP_PREF("throttle.version"))) {
1677
1
        Unused << Preferences::GetInt(HTTP_PREF("throttle.version"), &val);
1678
1
        mThrottleVersion = (uint32_t)clamped(val, 1, 2);
1679
1
    }
1680
1
1681
1
    if (PREF_CHANGED(HTTP_PREF("throttle.suspend-for"))) {
1682
1
        rv = Preferences::GetInt(HTTP_PREF("throttle.suspend-for"), &val);
1683
1
        mThrottleSuspendFor = (uint32_t)clamped(val, 0, 120000);
1684
1
        if (NS_SUCCEEDED(rv) && mConnMgr) {
1685
0
            Unused << mConnMgr->UpdateParam(nsHttpConnectionMgr::THROTTLING_SUSPEND_FOR,
1686
0
                                            mThrottleSuspendFor);
1687
0
        }
1688
1
    }
1689
1
1690
1
    if (PREF_CHANGED(HTTP_PREF("throttle.resume-for"))) {
1691
1
        rv = Preferences::GetInt(HTTP_PREF("throttle.resume-for"), &val);
1692
1
        mThrottleResumeFor = (uint32_t)clamped(val, 0, 120000);
1693
1
        if (NS_SUCCEEDED(rv) && mConnMgr) {
1694
0
            Unused << mConnMgr->UpdateParam(nsHttpConnectionMgr::THROTTLING_RESUME_FOR,
1695
0
                                            mThrottleResumeFor);
1696
0
        }
1697
1
    }
1698
1
1699
1
    if (PREF_CHANGED(HTTP_PREF("throttle.read-limit-bytes"))) {
1700
1
        rv = Preferences::GetInt(HTTP_PREF("throttle.read-limit-bytes"), &val);
1701
1
        mThrottleReadLimit = (uint32_t)clamped(val, 0, 500000);
1702
1
        if (NS_SUCCEEDED(rv) && mConnMgr) {
1703
0
            Unused << mConnMgr->UpdateParam(nsHttpConnectionMgr::THROTTLING_READ_LIMIT,
1704
0
                                            mThrottleReadLimit);
1705
0
        }
1706
1
    }
1707
1
1708
1
    if (PREF_CHANGED(HTTP_PREF("throttle.read-interval-ms"))) {
1709
1
        rv = Preferences::GetInt(HTTP_PREF("throttle.read-interval-ms"), &val);
1710
1
        mThrottleReadInterval = (uint32_t)clamped(val, 0, 120000);
1711
1
        if (NS_SUCCEEDED(rv) && mConnMgr) {
1712
0
            Unused << mConnMgr->UpdateParam(nsHttpConnectionMgr::THROTTLING_READ_INTERVAL,
1713
0
                                            mThrottleReadInterval);
1714
0
        }
1715
1
    }
1716
1
1717
1
    if (PREF_CHANGED(HTTP_PREF("throttle.hold-time-ms"))) {
1718
1
        rv = Preferences::GetInt(HTTP_PREF("throttle.hold-time-ms"), &val);
1719
1
        mThrottleHoldTime = (uint32_t)clamped(val, 0, 120000);
1720
1
        if (NS_SUCCEEDED(rv) && mConnMgr) {
1721
0
            Unused << mConnMgr->UpdateParam(nsHttpConnectionMgr::THROTTLING_HOLD_TIME,
1722
0
                                            mThrottleHoldTime);
1723
0
        }
1724
1
    }
1725
1
1726
1
    if (PREF_CHANGED(HTTP_PREF("throttle.max-time-ms"))) {
1727
1
      rv = Preferences::GetInt(HTTP_PREF("throttle.max-time-ms"), &val);
1728
1
      mThrottleMaxTime = (uint32_t)clamped(val, 0, 120000);
1729
1
      if (NS_SUCCEEDED(rv) && mConnMgr) {
1730
0
        Unused << mConnMgr->UpdateParam(nsHttpConnectionMgr::THROTTLING_MAX_TIME,
1731
0
                                        mThrottleMaxTime);
1732
0
      }
1733
1
    }
1734
1
1735
1
    if (PREF_CHANGED(HTTP_PREF("send_window_size"))) {
1736
1
      Unused << Preferences::GetInt(HTTP_PREF("send_window_size"), &val);
1737
1
      mSendWindowSize = val >= 0 ? val : 0;
1738
1
    }
1739
1
1740
1
    if (PREF_CHANGED(HTTP_PREF("on_click_priority"))) {
1741
1
        Unused << Preferences::GetBool(HTTP_PREF("on_click_priority"), &mUrgentStartEnabled);
1742
1
    }
1743
1
1744
1
    if (PREF_CHANGED(HTTP_PREF("tailing.enabled"))) {
1745
1
        Unused << Preferences::GetBool(HTTP_PREF("tailing.enabled"), &mTailBlockingEnabled);
1746
1
    }
1747
1
    if (PREF_CHANGED(HTTP_PREF("tailing.delay-quantum"))) {
1748
1
        Unused << Preferences::GetInt(HTTP_PREF("tailing.delay-quantum"), &val);
1749
1
        mTailDelayQuantum = (uint32_t)clamped(val, 0, 60000);
1750
1
    }
1751
1
    if (PREF_CHANGED(HTTP_PREF("tailing.delay-quantum-after-domcontentloaded"))) {
1752
1
        Unused << Preferences::GetInt(HTTP_PREF("tailing.delay-quantum-after-domcontentloaded"), &val);
1753
1
        mTailDelayQuantumAfterDCL = (uint32_t)clamped(val, 0, 60000);
1754
1
    }
1755
1
    if (PREF_CHANGED(HTTP_PREF("tailing.delay-max"))) {
1756
1
        Unused << Preferences::GetInt(HTTP_PREF("tailing.delay-max"), &val);
1757
1
        mTailDelayMax = (uint32_t)clamped(val, 0, 60000);
1758
1
    }
1759
1
    if (PREF_CHANGED(HTTP_PREF("tailing.total-max"))) {
1760
1
        Unused << Preferences::GetInt(HTTP_PREF("tailing.total-max"), &val);
1761
1
        mTailTotalMax = (uint32_t)clamped(val, 0, 60000);
1762
1
    }
1763
1
1764
1
    if (PREF_CHANGED(HTTP_PREF("focused_window_transaction_ratio"))) {
1765
1
        float ratio = 0;
1766
1
        rv = Preferences::GetFloat(HTTP_PREF("focused_window_transaction_ratio"), &ratio);
1767
1
        if (NS_SUCCEEDED(rv)) {
1768
1
            if (ratio > 0 && ratio < 1) {
1769
1
                mFocusedWindowTransactionRatio = ratio;
1770
1
            } else {
1771
0
                NS_WARNING("Wrong value for focused_window_transaction_ratio");
1772
0
            }
1773
1
        }
1774
1
    }
1775
1
1776
1
    //
1777
1
    // INTL options
1778
1
    //
1779
1
1780
1
    if (PREF_CHANGED(INTL_ACCEPT_LANGUAGES)) {
1781
1
        // We don't want to set the new accept languages here since
1782
1
        // this pref is a complex type and it may be racy with flushing
1783
1
        // string resources.
1784
1
        mAcceptLanguagesIsDirty = true;
1785
1
    }
1786
1
1787
1
    //
1788
1
    // Tracking options
1789
1
    //
1790
1
1791
1
    if (PREF_CHANGED(DONOTTRACK_HEADER_ENABLED)) {
1792
1
        cVar = false;
1793
1
        rv = Preferences::GetBool(DONOTTRACK_HEADER_ENABLED, &cVar);
1794
1
        if (NS_SUCCEEDED(rv)) {
1795
1
            mDoNotTrackEnabled = cVar;
1796
1
        }
1797
1
    }
1798
1
    // Hint option
1799
1
    if (PREF_CHANGED(SAFE_HINT_HEADER_VALUE)) {
1800
1
        cVar = false;
1801
1
        rv = Preferences::GetBool(SAFE_HINT_HEADER_VALUE, &cVar);
1802
1
        if (NS_SUCCEEDED(rv)) {
1803
0
            mSafeHintEnabled = cVar;
1804
0
        }
1805
1
    }
1806
1
1807
1
    // toggle to true anytime a token bucket related pref is changed.. that
1808
1
    // includes telemetry and allow-experiments because of the abtest profile
1809
1
    bool requestTokenBucketUpdated = false;
1810
1
1811
1
    //
1812
1
    // Telemetry
1813
1
    //
1814
1
1815
1
    if (PREF_CHANGED(TELEMETRY_ENABLED)) {
1816
1
        cVar = false;
1817
1
        requestTokenBucketUpdated = true;
1818
1
        rv = Preferences::GetBool(TELEMETRY_ENABLED, &cVar);
1819
1
        if (NS_SUCCEEDED(rv)) {
1820
1
            mTelemetryEnabled = cVar;
1821
1
        }
1822
1
    }
1823
1
1824
1
    // "security.ssl3.ecdhe_rsa_aes_128_gcm_sha256" is the required h2 interop
1825
1
    // suite.
1826
1
1827
1
    if (PREF_CHANGED(H2MANDATORY_SUITE)) {
1828
1
        cVar = false;
1829
1
        rv = Preferences::GetBool(H2MANDATORY_SUITE, &cVar);
1830
1
        if (NS_SUCCEEDED(rv)) {
1831
1
            mH2MandatorySuiteEnabled = cVar;
1832
1
        }
1833
1
    }
1834
1
1835
1
    //
1836
1
    // network.allow-experiments
1837
1
    //
1838
1
    if (PREF_CHANGED(ALLOW_EXPERIMENTS)) {
1839
1
        cVar = true;
1840
1
        requestTokenBucketUpdated = true;
1841
1
        rv = Preferences::GetBool(ALLOW_EXPERIMENTS, &cVar);
1842
1
        if (NS_SUCCEEDED(rv)) {
1843
1
            mAllowExperiments = cVar;
1844
1
        }
1845
1
    }
1846
1
1847
1
    // network.http.debug-observations
1848
1
    if (PREF_CHANGED("network.http.debug-observations")) {
1849
1
        cVar = false;
1850
1
        rv = Preferences::GetBool("network.http.debug-observations", &cVar);
1851
1
        if (NS_SUCCEEDED(rv)) {
1852
0
            mDebugObservations = cVar;
1853
0
        }
1854
1
    }
1855
1
1856
1
    if (PREF_CHANGED(HTTP_PREF("pacing.requests.enabled"))) {
1857
1
        rv = Preferences::GetBool(HTTP_PREF("pacing.requests.enabled"), &cVar);
1858
1
        if (NS_SUCCEEDED(rv)) {
1859
1
            mRequestTokenBucketEnabled = cVar;
1860
1
            requestTokenBucketUpdated = true;
1861
1
        }
1862
1
    }
1863
1
    if (PREF_CHANGED(HTTP_PREF("pacing.requests.min-parallelism"))) {
1864
1
        rv = Preferences::GetInt(HTTP_PREF("pacing.requests.min-parallelism"), &val);
1865
1
        if (NS_SUCCEEDED(rv)) {
1866
1
            mRequestTokenBucketMinParallelism = static_cast<uint16_t>(clamped(val, 1, 1024));
1867
1
            requestTokenBucketUpdated = true;
1868
1
        }
1869
1
    }
1870
1
    if (PREF_CHANGED(HTTP_PREF("pacing.requests.hz"))) {
1871
1
        rv = Preferences::GetInt(HTTP_PREF("pacing.requests.hz"), &val);
1872
1
        if (NS_SUCCEEDED(rv)) {
1873
1
            mRequestTokenBucketHz = static_cast<uint32_t>(clamped(val, 1, 10000));
1874
1
            requestTokenBucketUpdated = true;
1875
1
        }
1876
1
    }
1877
1
    if (PREF_CHANGED(HTTP_PREF("pacing.requests.burst"))) {
1878
1
        rv = Preferences::GetInt(HTTP_PREF("pacing.requests.burst"), &val);
1879
1
        if (NS_SUCCEEDED(rv)) {
1880
1
            mRequestTokenBucketBurst = val ? val : 1;
1881
1
            requestTokenBucketUpdated = true;
1882
1
        }
1883
1
    }
1884
1
    if (requestTokenBucketUpdated) {
1885
1
        MakeNewRequestTokenBucket();
1886
1
    }
1887
1
1888
1
    // Keepalive values for initial and idle connections.
1889
1
    if (PREF_CHANGED(HTTP_PREF("tcp_keepalive.short_lived_connections"))) {
1890
1
        rv = Preferences::GetBool(
1891
1
            HTTP_PREF("tcp_keepalive.short_lived_connections"), &cVar);
1892
1
        if (NS_SUCCEEDED(rv) && cVar != mTCPKeepaliveShortLivedEnabled) {
1893
1
            mTCPKeepaliveShortLivedEnabled = cVar;
1894
1
        }
1895
1
    }
1896
1
1897
1
    if (PREF_CHANGED(HTTP_PREF("tcp_keepalive.short_lived_time"))) {
1898
1
        rv = Preferences::GetInt(
1899
1
            HTTP_PREF("tcp_keepalive.short_lived_time"), &val);
1900
1
        if (NS_SUCCEEDED(rv) && val > 0)
1901
1
            mTCPKeepaliveShortLivedTimeS = clamped(val, 1, 300); // Max 5 mins.
1902
1
    }
1903
1
1904
1
    if (PREF_CHANGED(HTTP_PREF("tcp_keepalive.short_lived_idle_time"))) {
1905
1
        rv = Preferences::GetInt(
1906
1
            HTTP_PREF("tcp_keepalive.short_lived_idle_time"), &val);
1907
1
        if (NS_SUCCEEDED(rv) && val > 0)
1908
1
            mTCPKeepaliveShortLivedIdleTimeS = clamped(val,
1909
1
                                                       1, kMaxTCPKeepIdle);
1910
1
    }
1911
1
1912
1
    // Keepalive values for Long-lived Connections.
1913
1
    if (PREF_CHANGED(HTTP_PREF("tcp_keepalive.long_lived_connections"))) {
1914
1
        rv = Preferences::GetBool(
1915
1
            HTTP_PREF("tcp_keepalive.long_lived_connections"), &cVar);
1916
1
        if (NS_SUCCEEDED(rv) && cVar != mTCPKeepaliveLongLivedEnabled) {
1917
1
            mTCPKeepaliveLongLivedEnabled = cVar;
1918
1
        }
1919
1
    }
1920
1
1921
1
    if (PREF_CHANGED(HTTP_PREF("tcp_keepalive.long_lived_idle_time"))) {
1922
1
        rv = Preferences::GetInt(
1923
1
            HTTP_PREF("tcp_keepalive.long_lived_idle_time"), &val);
1924
1
        if (NS_SUCCEEDED(rv) && val > 0)
1925
1
            mTCPKeepaliveLongLivedIdleTimeS = clamped(val,
1926
1
                                                      1, kMaxTCPKeepIdle);
1927
1
    }
1928
1
1929
1
    if (PREF_CHANGED(HTTP_PREF("enforce-framing.http1")) ||
1930
1
        PREF_CHANGED(HTTP_PREF("enforce-framing.soft")) ) {
1931
1
        rv = Preferences::GetBool(HTTP_PREF("enforce-framing.http1"), &cVar);
1932
1
        if (NS_SUCCEEDED(rv) && cVar) {
1933
0
            mEnforceH1Framing = FRAMECHECK_STRICT;
1934
1
        } else {
1935
1
            rv = Preferences::GetBool(HTTP_PREF("enforce-framing.soft"), &cVar);
1936
1
            if (NS_SUCCEEDED(rv) && cVar) {
1937
1
                mEnforceH1Framing = FRAMECHECK_BARELY;
1938
1
            } else {
1939
0
                mEnforceH1Framing = FRAMECHECK_LAX;
1940
0
            }
1941
1
        }
1942
1
    }
1943
1
1944
1
    if (PREF_CHANGED(TCP_FAST_OPEN_ENABLE)) {
1945
1
        rv = Preferences::GetBool(TCP_FAST_OPEN_ENABLE, &cVar);
1946
1
        if (NS_SUCCEEDED(rv)) {
1947
1
            mUseFastOpen = cVar;
1948
1
        }
1949
1
    }
1950
1
1951
1
    if (PREF_CHANGED(TCP_FAST_OPEN_FAILURE_LIMIT)) {
1952
1
        rv = Preferences::GetInt(TCP_FAST_OPEN_FAILURE_LIMIT, &val);
1953
1
        if (NS_SUCCEEDED(rv)) {
1954
1
            if (val < 0) {
1955
0
                val = 0;
1956
0
            }
1957
1
            mFastOpenConsecutiveFailureLimit = val;
1958
1
        }
1959
1
    }
1960
1
1961
1
    if (PREF_CHANGED(TCP_FAST_OPEN_STALLS_LIMIT)) {
1962
1
        rv = Preferences::GetInt(TCP_FAST_OPEN_STALLS_LIMIT, &val);
1963
1
        if (NS_SUCCEEDED(rv)) {
1964
1
            if (val < 0) {
1965
0
                val = 0;
1966
0
            }
1967
1
            mFastOpenStallsLimit = val;
1968
1
        }
1969
1
    }
1970
1
1971
1
    if (PREF_CHANGED(TCP_FAST_OPEN_STALLS_TIMEOUT)) {
1972
1
        rv = Preferences::GetInt(TCP_FAST_OPEN_STALLS_TIMEOUT, &val);
1973
1
        if (NS_SUCCEEDED(rv)) {
1974
1
            if (val < 0) {
1975
0
                val = 0;
1976
0
            }
1977
1
            mFastOpenStallsTimeout = val;
1978
1
        }
1979
1
    }
1980
1
1981
1
    if (PREF_CHANGED(TCP_FAST_OPEN_STALLS_IDLE)) {
1982
1
        rv = Preferences::GetInt(TCP_FAST_OPEN_STALLS_IDLE, &val);
1983
1
        if (NS_SUCCEEDED(rv)) {
1984
1
            if (val < 0) {
1985
0
                val = 0;
1986
0
            }
1987
1
            mFastOpenStallsIdleTime = val;
1988
1
        }
1989
1
    }
1990
1
1991
1
    if (PREF_CHANGED(HTTP_PREF("spdy.default-hpack-buffer"))) {
1992
1
        rv = Preferences::GetInt(HTTP_PREF("spdy.default-hpack-buffer"), &val);
1993
1
        if (NS_SUCCEEDED(rv)) {
1994
1
            mDefaultHpackBuffer = val;
1995
1
        }
1996
1
    }
1997
1
1998
1
    // Enable HTTP response timeout if TCP Keepalives are disabled.
1999
1
    mResponseTimeoutEnabled = !mTCPKeepaliveShortLivedEnabled &&
2000
1
                              !mTCPKeepaliveLongLivedEnabled;
2001
1
2002
1
#undef PREF_CHANGED
2003
1
#undef MULTI_PREF_CHANGED
2004
1
}
2005
2006
/**
2007
 *  Allocates a C string into that contains a ISO 639 language list
2008
 *  notated with HTTP "q" values for output with a HTTP Accept-Language
2009
 *  header. Previous q values will be stripped because the order of
2010
 *  the langs imply the q value. The q values are calculated by dividing
2011
 *  1.0 amongst the number of languages present.
2012
 *
2013
 *  Ex: passing: "en, ja"
2014
 *      returns: "en,ja;q=0.5"
2015
 *
2016
 *      passing: "en, ja, fr_CA"
2017
 *      returns: "en,ja;q=0.7,fr_CA;q=0.3"
2018
 */
2019
static nsresult
2020
PrepareAcceptLanguages(const char *i_AcceptLanguages, nsACString &o_AcceptLanguages)
2021
0
{
2022
0
    if (!i_AcceptLanguages)
2023
0
        return NS_OK;
2024
0
2025
0
    const nsAutoCString ns_accept_languages(i_AcceptLanguages);
2026
0
    return rust_prepare_accept_languages(&ns_accept_languages,
2027
0
                                         &o_AcceptLanguages);
2028
0
}
2029
2030
nsresult
2031
nsHttpHandler::SetAcceptLanguages()
2032
0
{
2033
0
    mAcceptLanguagesIsDirty = false;
2034
0
2035
0
    nsAutoCString acceptLanguages;
2036
0
    Preferences::GetLocalizedCString(INTL_ACCEPT_LANGUAGES, acceptLanguages);
2037
0
2038
0
    nsAutoCString buf;
2039
0
    nsresult rv = PrepareAcceptLanguages(acceptLanguages.get(), buf);
2040
0
    if (NS_SUCCEEDED(rv)) {
2041
0
        mAcceptLanguages.Assign(buf);
2042
0
    }
2043
0
    return rv;
2044
0
}
2045
2046
nsresult
2047
nsHttpHandler::SetAccept(const char *aAccept)
2048
1
{
2049
1
    mAccept = aAccept;
2050
1
    return NS_OK;
2051
1
}
2052
2053
nsresult
2054
nsHttpHandler::SetAcceptEncodings(const char *aAcceptEncodings, bool isSecure)
2055
2
{
2056
2
    if (isSecure) {
2057
1
        mHttpsAcceptEncodings = aAcceptEncodings;
2058
1
    } else {
2059
1
        // use legacy list if a secure override is not specified
2060
1
        mHttpAcceptEncodings = aAcceptEncodings;
2061
1
        if (mHttpsAcceptEncodings.IsEmpty()) {
2062
1
            mHttpsAcceptEncodings = aAcceptEncodings;
2063
1
        }
2064
1
    }
2065
2
2066
2
    return NS_OK;
2067
2
}
2068
2069
//-----------------------------------------------------------------------------
2070
// nsHttpHandler::nsISupports
2071
//-----------------------------------------------------------------------------
2072
2073
NS_IMPL_ISUPPORTS(nsHttpHandler,
2074
                  nsIHttpProtocolHandler,
2075
                  nsIProxiedProtocolHandler,
2076
                  nsIProtocolHandler,
2077
                  nsIObserver,
2078
                  nsISupportsWeakReference,
2079
                  nsISpeculativeConnect)
2080
2081
//-----------------------------------------------------------------------------
2082
// nsHttpHandler::nsIProtocolHandler
2083
//-----------------------------------------------------------------------------
2084
2085
NS_IMETHODIMP
2086
nsHttpHandler::GetScheme(nsACString &aScheme)
2087
0
{
2088
0
    aScheme.AssignLiteral("http");
2089
0
    return NS_OK;
2090
0
}
2091
2092
NS_IMETHODIMP
2093
nsHttpHandler::GetDefaultPort(int32_t *result)
2094
0
{
2095
0
    *result = NS_HTTP_DEFAULT_PORT;
2096
0
    return NS_OK;
2097
0
}
2098
2099
NS_IMETHODIMP
2100
nsHttpHandler::GetProtocolFlags(uint32_t *result)
2101
11.5k
{
2102
11.5k
    *result = NS_HTTP_PROTOCOL_FLAGS;
2103
11.5k
    return NS_OK;
2104
11.5k
}
2105
2106
NS_IMETHODIMP
2107
nsHttpHandler::NewURI(const nsACString &aSpec,
2108
                      const char *aCharset,
2109
                      nsIURI *aBaseURI,
2110
                      nsIURI **aURI)
2111
1.06M
{
2112
1.06M
    return mozilla::net::NewURI(aSpec, aCharset, aBaseURI, NS_HTTP_DEFAULT_PORT, aURI);
2113
1.06M
}
2114
2115
NS_IMETHODIMP
2116
nsHttpHandler::NewChannel2(nsIURI* uri,
2117
                           nsILoadInfo* aLoadInfo,
2118
                           nsIChannel** result)
2119
0
{
2120
0
    LOG(("nsHttpHandler::NewChannel\n"));
2121
0
2122
0
    NS_ENSURE_ARG_POINTER(uri);
2123
0
    NS_ENSURE_ARG_POINTER(result);
2124
0
2125
0
    bool isHttp = false, isHttps = false;
2126
0
2127
0
    // Verify that we have been given a valid scheme
2128
0
    nsresult rv = uri->SchemeIs("http", &isHttp);
2129
0
    if (NS_FAILED(rv)) return rv;
2130
0
    if (!isHttp) {
2131
0
        rv = uri->SchemeIs("https", &isHttps);
2132
0
        if (NS_FAILED(rv)) return rv;
2133
0
        if (!isHttps) {
2134
0
            NS_WARNING("Invalid URI scheme");
2135
0
            return NS_ERROR_UNEXPECTED;
2136
0
        }
2137
0
    }
2138
0
2139
0
    return NewProxiedChannel2(uri, nullptr, 0, nullptr, aLoadInfo, result);
2140
0
}
2141
2142
NS_IMETHODIMP
2143
nsHttpHandler::NewChannel(nsIURI *uri, nsIChannel **result)
2144
0
{
2145
0
    return NewChannel2(uri, nullptr, result);
2146
0
}
2147
2148
NS_IMETHODIMP
2149
nsHttpHandler::AllowPort(int32_t port, const char *scheme, bool *_retval)
2150
0
{
2151
0
    // don't override anything.
2152
0
    *_retval = false;
2153
0
    return NS_OK;
2154
0
}
2155
2156
//-----------------------------------------------------------------------------
2157
// nsHttpHandler::nsIProxiedProtocolHandler
2158
//-----------------------------------------------------------------------------
2159
2160
NS_IMETHODIMP
2161
nsHttpHandler::NewProxiedChannel2(nsIURI *uri,
2162
                                  nsIProxyInfo* givenProxyInfo,
2163
                                  uint32_t proxyResolveFlags,
2164
                                  nsIURI *proxyURI,
2165
                                  nsILoadInfo* aLoadInfo,
2166
                                  nsIChannel** result)
2167
0
{
2168
0
    RefPtr<HttpBaseChannel> httpChannel;
2169
0
2170
0
    LOG(("nsHttpHandler::NewProxiedChannel [proxyInfo=%p]\n",
2171
0
        givenProxyInfo));
2172
0
2173
#ifdef MOZ_TASK_TRACER
2174
    if (tasktracer::IsStartLogging()) {
2175
        nsAutoCString urispec;
2176
        uri->GetSpec(urispec);
2177
        tasktracer::AddLabel("nsHttpHandler::NewProxiedChannel2 %s", urispec.get());
2178
    }
2179
#endif
2180
2181
0
    nsCOMPtr<nsProxyInfo> proxyInfo;
2182
0
    if (givenProxyInfo) {
2183
0
        proxyInfo = do_QueryInterface(givenProxyInfo);
2184
0
        NS_ENSURE_ARG(proxyInfo);
2185
0
    }
2186
0
2187
0
    bool https;
2188
0
    nsresult rv = uri->SchemeIs("https", &https);
2189
0
    if (NS_FAILED(rv))
2190
0
        return rv;
2191
0
2192
0
    if (IsNeckoChild()) {
2193
0
        httpChannel = new HttpChannelChild();
2194
0
    } else {
2195
0
        httpChannel = new nsHttpChannel();
2196
0
    }
2197
0
2198
0
    uint32_t caps = mCapabilities;
2199
0
2200
0
    if (!IsNeckoChild()) {
2201
0
        // HACK: make sure PSM gets initialized on the main thread.
2202
0
        net_EnsurePSMInit();
2203
0
    }
2204
0
2205
0
    if (XRE_IsParentProcess()) {
2206
0
        // Load UserAgentOverrides.jsm before any HTTP request is issued.
2207
0
        EnsureUAOverridesInit();
2208
0
    }
2209
0
2210
0
    uint64_t channelId;
2211
0
    rv = NewChannelId(channelId);
2212
0
    NS_ENSURE_SUCCESS(rv, rv);
2213
0
2214
0
    rv = httpChannel->Init(uri, caps, proxyInfo, proxyResolveFlags, proxyURI, channelId);
2215
0
    if (NS_FAILED(rv))
2216
0
        return rv;
2217
0
2218
0
    // set the loadInfo on the new channel
2219
0
    rv = httpChannel->SetLoadInfo(aLoadInfo);
2220
0
    if (NS_FAILED(rv)) {
2221
0
        return rv;
2222
0
    }
2223
0
2224
0
    httpChannel.forget(result);
2225
0
    return NS_OK;
2226
0
}
2227
2228
NS_IMETHODIMP
2229
nsHttpHandler::NewProxiedChannel(nsIURI *uri,
2230
                                 nsIProxyInfo* givenProxyInfo,
2231
                                 uint32_t proxyResolveFlags,
2232
                                 nsIURI *proxyURI,
2233
                                 nsIChannel **result)
2234
0
{
2235
0
    return NewProxiedChannel2(uri, givenProxyInfo,
2236
0
                              proxyResolveFlags, proxyURI,
2237
0
                              nullptr, result);
2238
0
}
2239
2240
//-----------------------------------------------------------------------------
2241
// nsHttpHandler::nsIHttpProtocolHandler
2242
//-----------------------------------------------------------------------------
2243
2244
NS_IMETHODIMP
2245
nsHttpHandler::GetUserAgent(nsACString &value)
2246
0
{
2247
0
    value = UserAgent();
2248
0
    return NS_OK;
2249
0
}
2250
2251
NS_IMETHODIMP
2252
nsHttpHandler::GetAppName(nsACString &value)
2253
0
{
2254
0
    value = mLegacyAppName;
2255
0
    return NS_OK;
2256
0
}
2257
2258
NS_IMETHODIMP
2259
nsHttpHandler::GetAppVersion(nsACString &value)
2260
0
{
2261
0
    value = mLegacyAppVersion;
2262
0
    return NS_OK;
2263
0
}
2264
2265
NS_IMETHODIMP
2266
nsHttpHandler::GetPlatform(nsACString &value)
2267
0
{
2268
0
    value = mPlatform;
2269
0
    return NS_OK;
2270
0
}
2271
2272
NS_IMETHODIMP
2273
nsHttpHandler::GetOscpu(nsACString &value)
2274
0
{
2275
0
    value = mOscpu;
2276
0
    return NS_OK;
2277
0
}
2278
2279
NS_IMETHODIMP
2280
nsHttpHandler::GetMisc(nsACString &value)
2281
0
{
2282
0
    value = mMisc;
2283
0
    return NS_OK;
2284
0
}
2285
2286
//-----------------------------------------------------------------------------
2287
// nsHttpHandler::nsIObserver
2288
//-----------------------------------------------------------------------------
2289
2290
static bool CanEnableSpeculativeConnect(); // forward declaration
2291
2292
NS_IMETHODIMP
2293
nsHttpHandler::Observe(nsISupports *subject,
2294
                       const char *topic,
2295
                       const char16_t *data)
2296
0
{
2297
0
    MOZ_ASSERT(NS_IsMainThread());
2298
0
    LOG(("nsHttpHandler::Observe [topic=\"%s\"]\n", topic));
2299
0
2300
0
    nsresult rv;
2301
0
    if (!strcmp(topic, "profile-change-net-teardown") ||
2302
0
        !strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) ) {
2303
0
2304
0
        mHandlerActive = false;
2305
0
2306
0
        // clear cache of all authentication credentials.
2307
0
        Unused << mAuthCache.ClearAll();
2308
0
        Unused << mPrivateAuthCache.ClearAll();
2309
0
        if (mWifiTickler)
2310
0
            mWifiTickler->Cancel();
2311
0
2312
0
        // Inform nsIOService that network is tearing down.
2313
0
        gIOService->SetHttpHandlerAlreadyShutingDown();
2314
0
2315
0
        ShutdownConnectionManager();
2316
0
2317
0
        // need to reset the session start time since cache validation may
2318
0
        // depend on this value.
2319
0
        mSessionStartTime = NowInSeconds();
2320
0
2321
0
        if (!mDoNotTrackEnabled) {
2322
0
            Telemetry::Accumulate(Telemetry::DNT_USAGE, 2);
2323
0
        } else {
2324
0
            Telemetry::Accumulate(Telemetry::DNT_USAGE, 1);
2325
0
        }
2326
0
2327
0
        if (UseFastOpen()) {
2328
0
            Telemetry::Accumulate(Telemetry::TCP_FAST_OPEN_STATUS, 0);
2329
0
        } else if (!mFastOpenSupported) {
2330
0
            Telemetry::Accumulate(Telemetry::TCP_FAST_OPEN_STATUS, 1);
2331
0
        } else if (!mUseFastOpen) {
2332
0
            Telemetry::Accumulate(Telemetry::TCP_FAST_OPEN_STATUS, 2);
2333
0
        } else if (mFastOpenConsecutiveFailureCounter >= mFastOpenConsecutiveFailureLimit) {
2334
0
            Telemetry::Accumulate(Telemetry::TCP_FAST_OPEN_STATUS, 3);
2335
0
        } else {
2336
0
            Telemetry::Accumulate(Telemetry::TCP_FAST_OPEN_STATUS, 4);
2337
0
        }
2338
0
    } else if (!strcmp(topic, "profile-change-net-restore")) {
2339
0
        // initialize connection manager
2340
0
        rv = InitConnectionMgr();
2341
0
        MOZ_ASSERT(NS_SUCCEEDED(rv));
2342
0
    } else if (!strcmp(topic, "net:clear-active-logins")) {
2343
0
        Unused << mAuthCache.ClearAll();
2344
0
        Unused << mPrivateAuthCache.ClearAll();
2345
0
    } else if (!strcmp(topic, "net:cancel-all-connections")) {
2346
0
        if (mConnMgr) {
2347
0
            mConnMgr->AbortAndCloseAllConnections(0, nullptr);
2348
0
        }
2349
0
    } else if (!strcmp(topic, "net:prune-dead-connections")) {
2350
0
        if (mConnMgr) {
2351
0
            rv = mConnMgr->PruneDeadConnections();
2352
0
            if (NS_FAILED(rv)) {
2353
0
                LOG(("    PruneDeadConnections failed (%08x)\n",
2354
0
                     static_cast<uint32_t>(rv)));
2355
0
            }
2356
0
        }
2357
0
    } else if (!strcmp(topic, "net:prune-all-connections")) {
2358
0
        if (mConnMgr) {
2359
0
            rv = mConnMgr->DoShiftReloadConnectionCleanup(nullptr);
2360
0
            if (NS_FAILED(rv)) {
2361
0
                LOG(("    DoShiftReloadConnectionCleanup failed (%08x)\n",
2362
0
                     static_cast<uint32_t>(rv)));
2363
0
            }
2364
0
            rv = mConnMgr->PruneDeadConnections();
2365
0
            if (NS_FAILED(rv)) {
2366
0
                LOG(("    PruneDeadConnections failed (%08x)\n",
2367
0
                     static_cast<uint32_t>(rv)));
2368
0
            }
2369
0
        }
2370
#if 0
2371
    } else if (!strcmp(topic, "net:failed-to-process-uri-content")) {
2372
         // nop right now - we used to cancel h1 pipelines based on this,
2373
         // but those are no longer implemented
2374
         nsCOMPtr<nsIURI> uri = do_QueryInterface(subject);
2375
#endif
2376
0
    } else if (!strcmp(topic, "last-pb-context-exited")) {
2377
0
        Unused << mPrivateAuthCache.ClearAll();
2378
0
        if (mConnMgr) {
2379
0
            mConnMgr->ClearAltServiceMappings();
2380
0
        }
2381
0
    } else if (!strcmp(topic, "browser:purge-session-history")) {
2382
0
        if (mConnMgr) {
2383
0
            if (gSocketTransportService) {
2384
0
              nsCOMPtr<nsIRunnable> event = NewRunnableMethod(
2385
0
                "net::nsHttpConnectionMgr::ClearConnectionHistory",
2386
0
                mConnMgr,
2387
0
                &nsHttpConnectionMgr::ClearConnectionHistory);
2388
0
              gSocketTransportService->Dispatch(event, NS_DISPATCH_NORMAL);
2389
0
            }
2390
0
            mConnMgr->ClearAltServiceMappings();
2391
0
        }
2392
0
    } else if (!strcmp(topic, NS_NETWORK_LINK_TOPIC)) {
2393
0
        nsAutoCString converted = NS_ConvertUTF16toUTF8(data);
2394
0
        if (!strcmp(converted.get(), NS_NETWORK_LINK_DATA_CHANGED)) {
2395
0
            if (mConnMgr) {
2396
0
                rv = mConnMgr->PruneDeadConnections();
2397
0
                if (NS_FAILED(rv)) {
2398
0
                    LOG(("    PruneDeadConnections failed (%08x)\n",
2399
0
                         static_cast<uint32_t>(rv)));
2400
0
                }
2401
0
                rv = mConnMgr->VerifyTraffic();
2402
0
                if (NS_FAILED(rv)) {
2403
0
                    LOG(("    VerifyTraffic failed (%08x)\n",
2404
0
                         static_cast<uint32_t>(rv)));
2405
0
                }
2406
0
            }
2407
0
        }
2408
0
    } else if (!strcmp(topic, "application-background")) {
2409
0
        // going to the background on android means we should close
2410
0
        // down idle connections for power conservation
2411
0
        if (mConnMgr) {
2412
0
            rv = mConnMgr->DoShiftReloadConnectionCleanup(nullptr);
2413
0
            if (NS_FAILED(rv)) {
2414
0
                LOG(("    DoShiftReloadConnectionCleanup failed (%08x)\n",
2415
0
                     static_cast<uint32_t>(rv)));
2416
0
            }
2417
0
        }
2418
0
    } else if (!strcmp(topic, "net:current-toplevel-outer-content-windowid")) {
2419
0
        nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(subject);
2420
0
        MOZ_RELEASE_ASSERT(wrapper);
2421
0
2422
0
        uint64_t windowId = 0;
2423
0
        wrapper->GetData(&windowId);
2424
0
        MOZ_ASSERT(windowId);
2425
0
2426
0
        static uint64_t sCurrentTopLevelOuterContentWindowId = 0;
2427
0
        if (sCurrentTopLevelOuterContentWindowId != windowId) {
2428
0
            sCurrentTopLevelOuterContentWindowId = windowId;
2429
0
            if (mConnMgr) {
2430
0
                mConnMgr->UpdateCurrentTopLevelOuterContentWindowId(
2431
0
                    sCurrentTopLevelOuterContentWindowId);
2432
0
            }
2433
0
        }
2434
0
    } else if (!strcmp(topic, "captive-portal-login") ||
2435
0
               !strcmp(topic, "captive-portal-login-success")) {
2436
0
         // We have detected a captive portal and we will reset the Fast Open
2437
0
         // failure counter.
2438
0
         ResetFastOpenConsecutiveFailureCounter();
2439
0
    } else if (!strcmp(topic, "psm:user-certificate-added")) {
2440
0
        // A user certificate has just been added.
2441
0
        // We should immediately disable speculative connect
2442
0
        mSpeculativeConnectEnabled = false;
2443
0
    } else if (!strcmp(topic, "psm:user-certificate-deleted")) {
2444
0
        // If a user certificate has been removed, we need to check if there
2445
0
        // are others installed
2446
0
        mSpeculativeConnectEnabled = CanEnableSpeculativeConnect();
2447
0
    } else if (!strcmp(topic, "intl:app-locales-changed")) {
2448
0
        // If the locale changed, there's a chance the accept language did too
2449
0
        mAcceptLanguagesIsDirty = true;
2450
0
    }
2451
0
2452
0
    return NS_OK;
2453
0
}
2454
2455
// nsISpeculativeConnect
2456
2457
static bool
2458
CanEnableSpeculativeConnect()
2459
0
{
2460
0
  MOZ_ASSERT(NS_IsMainThread(), "Main thread only");
2461
0
2462
0
  nsCOMPtr<nsINSSComponent> component(do_GetService(PSM_COMPONENT_CONTRACTID));
2463
0
  if (!component) {
2464
0
    return false;
2465
0
  }
2466
0
2467
0
  // Check if any 3rd party PKCS#11 module are installed, as they may produce
2468
0
  // client certificates
2469
0
  bool activeSmartCards = false;
2470
0
  nsresult rv = component->HasActiveSmartCards(&activeSmartCards);
2471
0
  if (NS_FAILED(rv) || activeSmartCards) {
2472
0
    return false;
2473
0
  }
2474
0
2475
0
  // If there are any client certificates installed, we can't enable speculative
2476
0
  // connect, as it may pop up the certificate chooser at any time.
2477
0
  bool hasUserCerts = false;
2478
0
  rv = component->HasUserCertsInstalled(&hasUserCerts);
2479
0
  if (NS_FAILED(rv) || hasUserCerts) {
2480
0
    return false;
2481
0
  }
2482
0
2483
0
  return true;
2484
0
}
2485
2486
nsresult
2487
nsHttpHandler::SpeculativeConnectInternal(nsIURI *aURI,
2488
                                          nsIPrincipal *aPrincipal,
2489
                                          nsIInterfaceRequestor *aCallbacks,
2490
                                          bool anonymous)
2491
0
{
2492
0
    if (IsNeckoChild()) {
2493
0
        ipc::URIParams params;
2494
0
        SerializeURI(aURI, params);
2495
0
        gNeckoChild->SendSpeculativeConnect(params,
2496
0
                                            IPC::Principal(aPrincipal),
2497
0
                                            anonymous);
2498
0
        return NS_OK;
2499
0
    }
2500
0
2501
0
    if (!mHandlerActive)
2502
0
        return NS_OK;
2503
0
2504
0
    MOZ_ASSERT(NS_IsMainThread());
2505
0
    nsCOMPtr<nsIObserverService> obsService = services::GetObserverService();
2506
0
    if (mDebugObservations && obsService) {
2507
0
        // this is basically used for test coverage of an otherwise 'hintable'
2508
0
        // feature
2509
0
        obsService->NotifyObservers(nullptr, "speculative-connect-request",
2510
0
                                    nullptr);
2511
0
        for (auto* cp : dom::ContentParent::AllProcesses(dom::ContentParent::eLive)) {
2512
0
            PNeckoParent* neckoParent = SingleManagedOrNull(cp->ManagedPNeckoParent());
2513
0
            if (!neckoParent) {
2514
0
                continue;
2515
0
            }
2516
0
            Unused << neckoParent->SendSpeculativeConnectRequest();
2517
0
        }
2518
0
    }
2519
0
2520
0
    nsISiteSecurityService* sss = gHttpHandler->GetSSService();
2521
0
    bool isStsHost = false;
2522
0
    if (!sss)
2523
0
        return NS_OK;
2524
0
2525
0
    nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(aCallbacks);
2526
0
    uint32_t flags = 0;
2527
0
    if (loadContext && loadContext->UsePrivateBrowsing())
2528
0
        flags |= nsISocketProvider::NO_PERMANENT_STORAGE;
2529
0
2530
0
    OriginAttributes originAttributes;
2531
0
    // If the principal is given, we use the originAttributes from this
2532
0
    // principal. Otherwise, we use the originAttributes from the
2533
0
    // loadContext.
2534
0
    if (aPrincipal) {
2535
0
        originAttributes = aPrincipal->OriginAttributesRef();
2536
0
    } else if (loadContext) {
2537
0
        loadContext->GetOriginAttributes(originAttributes);
2538
0
    }
2539
0
2540
0
    nsCOMPtr<nsIURI> clone;
2541
0
    if (NS_SUCCEEDED(sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS,
2542
0
                                      aURI, flags, originAttributes,
2543
0
                                      nullptr, nullptr, &isStsHost)) &&
2544
0
                                      isStsHost) {
2545
0
        if (NS_SUCCEEDED(NS_GetSecureUpgradedURI(aURI,
2546
0
                                                 getter_AddRefs(clone)))) {
2547
0
            aURI = clone.get();
2548
0
            // (NOTE: We better make sure |clone| stays alive until the end
2549
0
            // of the function now, since our aURI arg now points to it!)
2550
0
        }
2551
0
    }
2552
0
2553
0
    nsAutoCString scheme;
2554
0
    nsresult rv = aURI->GetScheme(scheme);
2555
0
    if (NS_FAILED(rv))
2556
0
        return rv;
2557
0
2558
0
    // If this is HTTPS, make sure PSM is initialized as the channel
2559
0
    // creation path may have been bypassed
2560
0
    if (scheme.EqualsLiteral("https")) {
2561
0
        if (!IsNeckoChild()) {
2562
0
            // make sure PSM gets initialized on the main thread.
2563
0
            net_EnsurePSMInit();
2564
0
        }
2565
0
    }
2566
0
    // Ensure that this is HTTP or HTTPS, otherwise we don't do preconnect here
2567
0
    else if (!scheme.EqualsLiteral("http"))
2568
0
        return NS_ERROR_UNEXPECTED;
2569
0
2570
0
    // Construct connection info object
2571
0
    bool usingSSL = false;
2572
0
    rv = aURI->SchemeIs("https", &usingSSL);
2573
0
    if (NS_FAILED(rv))
2574
0
        return rv;
2575
0
2576
0
    static bool sCheckedIfSpeculativeEnabled = false;
2577
0
    if (!sCheckedIfSpeculativeEnabled) {
2578
0
        sCheckedIfSpeculativeEnabled = true;
2579
0
        mSpeculativeConnectEnabled = CanEnableSpeculativeConnect();
2580
0
    }
2581
0
2582
0
    if (usingSSL && !mSpeculativeConnectEnabled) {
2583
0
        return NS_ERROR_UNEXPECTED;
2584
0
    }
2585
0
2586
0
    nsAutoCString host;
2587
0
    rv = aURI->GetAsciiHost(host);
2588
0
    if (NS_FAILED(rv))
2589
0
        return rv;
2590
0
2591
0
    int32_t port = -1;
2592
0
    rv = aURI->GetPort(&port);
2593
0
    if (NS_FAILED(rv))
2594
0
        return rv;
2595
0
2596
0
    nsAutoCString username;
2597
0
    aURI->GetUsername(username);
2598
0
2599
0
    auto *ci =
2600
0
        new nsHttpConnectionInfo(host, port, EmptyCString(), username, nullptr,
2601
0
                                 originAttributes, usingSSL);
2602
0
    ci->SetAnonymous(anonymous);
2603
0
2604
0
    return SpeculativeConnect(ci, aCallbacks);
2605
0
}
2606
2607
NS_IMETHODIMP
2608
nsHttpHandler::SpeculativeConnect(nsIURI *aURI,
2609
                                  nsIInterfaceRequestor *aCallbacks)
2610
0
{
2611
0
    return SpeculativeConnectInternal(aURI, nullptr, aCallbacks, false);
2612
0
}
2613
2614
NS_IMETHODIMP
2615
nsHttpHandler::SpeculativeConnect2(nsIURI *aURI,
2616
                                   nsIPrincipal *aPrincipal,
2617
                                   nsIInterfaceRequestor *aCallbacks)
2618
0
{
2619
0
    return SpeculativeConnectInternal(aURI, aPrincipal, aCallbacks, false);
2620
0
}
2621
2622
NS_IMETHODIMP
2623
nsHttpHandler::SpeculativeAnonymousConnect(nsIURI *aURI,
2624
                                           nsIInterfaceRequestor *aCallbacks)
2625
0
{
2626
0
    return SpeculativeConnectInternal(aURI, nullptr, aCallbacks, true);
2627
0
}
2628
2629
NS_IMETHODIMP
2630
nsHttpHandler::SpeculativeAnonymousConnect2(nsIURI *aURI,
2631
                                            nsIPrincipal *aPrincipal,
2632
                                            nsIInterfaceRequestor *aCallbacks)
2633
0
{
2634
0
    return SpeculativeConnectInternal(aURI, aPrincipal, aCallbacks, true);
2635
0
}
2636
2637
void
2638
nsHttpHandler::TickleWifi(nsIInterfaceRequestor *cb)
2639
0
{
2640
0
    if (!cb || !mWifiTickler)
2641
0
        return;
2642
0
2643
0
    // If B2G requires a similar mechanism nsINetworkManager, currently only avail
2644
0
    // on B2G, contains the necessary information on wifi and gateway
2645
0
2646
0
    nsCOMPtr<nsIDOMWindow> domWindow = do_GetInterface(cb);
2647
0
    nsCOMPtr<nsPIDOMWindowOuter> piWindow = do_QueryInterface(domWindow);
2648
0
    if (!piWindow)
2649
0
        return;
2650
0
2651
0
    RefPtr<dom::Navigator> navigator = piWindow->GetNavigator();
2652
0
    if (!navigator)
2653
0
        return;
2654
0
2655
0
    nsCOMPtr<nsINetworkProperties> networkProperties =
2656
0
        navigator->GetNetworkProperties();
2657
0
    if (!networkProperties)
2658
0
        return;
2659
0
2660
0
    uint32_t gwAddress;
2661
0
    bool isWifi;
2662
0
    nsresult rv;
2663
0
2664
0
    rv = networkProperties->GetDhcpGateway(&gwAddress);
2665
0
    if (NS_SUCCEEDED(rv))
2666
0
        rv = networkProperties->GetIsWifi(&isWifi);
2667
0
    if (NS_FAILED(rv))
2668
0
        return;
2669
0
2670
0
    if (!gwAddress || !isWifi)
2671
0
        return;
2672
0
2673
0
    mWifiTickler->SetIPV4Address(gwAddress);
2674
0
    mWifiTickler->Tickle();
2675
0
}
2676
2677
//-----------------------------------------------------------------------------
2678
// nsHttpsHandler implementation
2679
//-----------------------------------------------------------------------------
2680
2681
NS_IMPL_ISUPPORTS(nsHttpsHandler,
2682
                  nsIHttpProtocolHandler,
2683
                  nsIProxiedProtocolHandler,
2684
                  nsIProtocolHandler,
2685
                  nsISupportsWeakReference,
2686
                  nsISpeculativeConnect)
2687
2688
nsresult
2689
nsHttpsHandler::Init()
2690
1
{
2691
1
    nsCOMPtr<nsIProtocolHandler> httpHandler(
2692
1
            do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http"));
2693
1
    MOZ_ASSERT(httpHandler.get() != nullptr);
2694
1
    return NS_OK;
2695
1
}
2696
2697
NS_IMETHODIMP
2698
nsHttpsHandler::GetScheme(nsACString &aScheme)
2699
0
{
2700
0
    aScheme.AssignLiteral("https");
2701
0
    return NS_OK;
2702
0
}
2703
2704
NS_IMETHODIMP
2705
nsHttpsHandler::GetDefaultPort(int32_t *aPort)
2706
0
{
2707
0
    *aPort = NS_HTTPS_DEFAULT_PORT;
2708
0
    return NS_OK;
2709
0
}
2710
2711
NS_IMETHODIMP
2712
nsHttpsHandler::GetProtocolFlags(uint32_t *aProtocolFlags)
2713
0
{
2714
0
    *aProtocolFlags = NS_HTTP_PROTOCOL_FLAGS | URI_IS_POTENTIALLY_TRUSTWORTHY;
2715
0
    return NS_OK;
2716
0
}
2717
2718
NS_IMETHODIMP
2719
nsHttpsHandler::NewURI(const nsACString &aSpec,
2720
                       const char *aOriginCharset,
2721
                       nsIURI *aBaseURI,
2722
                       nsIURI **_retval)
2723
247
{
2724
247
    return mozilla::net::NewURI(aSpec, aOriginCharset, aBaseURI, NS_HTTPS_DEFAULT_PORT, _retval);
2725
247
}
2726
2727
NS_IMETHODIMP
2728
nsHttpsHandler::NewChannel2(nsIURI* aURI,
2729
                            nsILoadInfo* aLoadInfo,
2730
                            nsIChannel** _retval)
2731
0
{
2732
0
    MOZ_ASSERT(gHttpHandler);
2733
0
    if (!gHttpHandler)
2734
0
      return NS_ERROR_UNEXPECTED;
2735
0
    return gHttpHandler->NewChannel2(aURI, aLoadInfo, _retval);
2736
0
}
2737
2738
NS_IMETHODIMP
2739
nsHttpsHandler::NewChannel(nsIURI *aURI, nsIChannel **_retval)
2740
0
{
2741
0
    return NewChannel2(aURI, nullptr, _retval);
2742
0
}
2743
2744
NS_IMETHODIMP
2745
nsHttpsHandler::AllowPort(int32_t aPort, const char *aScheme, bool *_retval)
2746
0
{
2747
0
    // don't override anything.
2748
0
    *_retval = false;
2749
0
    return NS_OK;
2750
0
}
2751
2752
void
2753
nsHttpHandler::ShutdownConnectionManager()
2754
0
{
2755
0
    // ensure connection manager is shutdown
2756
0
    if (mConnMgr) {
2757
0
        nsresult rv = mConnMgr->Shutdown();
2758
0
        if (NS_FAILED(rv)) {
2759
0
            LOG(("nsHttpHandler::ShutdownConnectionManager\n"
2760
0
                 "    failed to shutdown connection manager\n"));
2761
0
        }
2762
0
    }
2763
0
}
2764
2765
nsresult
2766
nsHttpHandler::NewChannelId(uint64_t& channelId)
2767
0
{
2768
0
  MOZ_ASSERT(NS_IsMainThread());
2769
0
  channelId = ((static_cast<uint64_t>(mProcessId) << 32) & 0xFFFFFFFF00000000LL) | mNextChannelId++;
2770
0
  return NS_OK;
2771
0
}
2772
2773
void
2774
nsHttpHandler::NotifyActiveTabLoadOptimization()
2775
0
{
2776
0
  SetLastActiveTabLoadOptimizationHit(TimeStamp::Now());
2777
0
}
2778
2779
TimeStamp const nsHttpHandler::GetLastActiveTabLoadOptimizationHit()
2780
0
{
2781
0
  MutexAutoLock lock(mLastActiveTabLoadOptimizationLock);
2782
0
2783
0
  return mLastActiveTabLoadOptimizationHit;
2784
0
}
2785
2786
void
2787
nsHttpHandler::SetLastActiveTabLoadOptimizationHit(TimeStamp const &when)
2788
0
{
2789
0
  MutexAutoLock lock(mLastActiveTabLoadOptimizationLock);
2790
0
2791
0
  if (mLastActiveTabLoadOptimizationHit.IsNull() ||
2792
0
      (!when.IsNull() && mLastActiveTabLoadOptimizationHit < when)) {
2793
0
    mLastActiveTabLoadOptimizationHit = when;
2794
0
  }
2795
0
}
2796
2797
bool
2798
nsHttpHandler::IsBeforeLastActiveTabLoadOptimization(TimeStamp const &when)
2799
0
{
2800
0
  MutexAutoLock lock(mLastActiveTabLoadOptimizationLock);
2801
0
2802
0
  return !mLastActiveTabLoadOptimizationHit.IsNull() &&
2803
0
         when <= mLastActiveTabLoadOptimizationHit;
2804
0
}
2805
2806
} // namespace net
2807
} // namespace mozilla