netwerk/protocol/http/nsHttpHandler.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
michael@0 2 /* vim:set ts=4 sw=4 sts=4 et cin: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 // HttpLog.h should generally be included first
michael@0 8 #include "HttpLog.h"
michael@0 9
michael@0 10 #include "nsHttp.h"
michael@0 11 #include "nsHttpHandler.h"
michael@0 12 #include "nsHttpChannel.h"
michael@0 13 #include "nsHttpAuthCache.h"
michael@0 14 #include "nsStandardURL.h"
michael@0 15 #include "nsIDOMWindow.h"
michael@0 16 #include "nsIDOMNavigator.h"
michael@0 17 #include "nsIMozNavigatorNetwork.h"
michael@0 18 #include "nsINetworkProperties.h"
michael@0 19 #include "nsIHttpChannel.h"
michael@0 20 #include "nsIStandardURL.h"
michael@0 21 #include "LoadContextInfo.h"
michael@0 22 #include "nsCategoryManagerUtils.h"
michael@0 23 #include "nsIPrefService.h"
michael@0 24 #include "nsIPrefBranch.h"
michael@0 25 #include "nsIPrefLocalizedString.h"
michael@0 26 #include "nsISocketProviderService.h"
michael@0 27 #include "nsISocketProvider.h"
michael@0 28 #include "nsPrintfCString.h"
michael@0 29 #include "nsCOMPtr.h"
michael@0 30 #include "nsNetCID.h"
michael@0 31 #include "prprf.h"
michael@0 32 #include "nsNetUtil.h"
michael@0 33 #include "nsAsyncRedirectVerifyHelper.h"
michael@0 34 #include "nsSocketTransportService2.h"
michael@0 35 #include "nsAlgorithm.h"
michael@0 36 #include "ASpdySession.h"
michael@0 37 #include "mozIApplicationClearPrivateDataParams.h"
michael@0 38 #include "EventTokenBucket.h"
michael@0 39 #include "Tickler.h"
michael@0 40 #include "nsIXULAppInfo.h"
michael@0 41 #include "nsICacheSession.h"
michael@0 42 #include "nsICookieService.h"
michael@0 43 #include "nsIObserverService.h"
michael@0 44 #include "nsISiteSecurityService.h"
michael@0 45 #include "nsIStreamConverterService.h"
michael@0 46 #include "nsITimer.h"
michael@0 47 #include "nsCRT.h"
michael@0 48 #include "SpdyZlibReporter.h"
michael@0 49 #include "nsIMemoryReporter.h"
michael@0 50 #include "nsIParentalControlsService.h"
michael@0 51
michael@0 52 #include "mozilla/net/NeckoChild.h"
michael@0 53 #include "mozilla/Telemetry.h"
michael@0 54
michael@0 55 #if defined(XP_UNIX)
michael@0 56 #include <sys/utsname.h>
michael@0 57 #endif
michael@0 58
michael@0 59 #if defined(XP_WIN)
michael@0 60 #include <windows.h>
michael@0 61 #endif
michael@0 62
michael@0 63 #if defined(XP_MACOSX)
michael@0 64 #include <CoreServices/CoreServices.h>
michael@0 65 #include "nsCocoaFeatures.h"
michael@0 66 #endif
michael@0 67
michael@0 68 //-----------------------------------------------------------------------------
michael@0 69 #include "mozilla/net/HttpChannelChild.h"
michael@0 70
michael@0 71
michael@0 72 #ifdef DEBUG
michael@0 73 // defined by the socket transport service while active
michael@0 74 extern PRThread *gSocketThread;
michael@0 75 #endif
michael@0 76
michael@0 77 #define UA_PREF_PREFIX "general.useragent."
michael@0 78 #ifdef XP_WIN
michael@0 79 #define UA_SPARE_PLATFORM
michael@0 80 #endif
michael@0 81
michael@0 82 #define HTTP_PREF_PREFIX "network.http."
michael@0 83 #define INTL_ACCEPT_LANGUAGES "intl.accept_languages"
michael@0 84 #define BROWSER_PREF_PREFIX "browser.cache."
michael@0 85 #define DONOTTRACK_HEADER_ENABLED "privacy.donottrackheader.enabled"
michael@0 86 #define DONOTTRACK_HEADER_VALUE "privacy.donottrackheader.value"
michael@0 87 #define DONOTTRACK_VALUE_UNSET 2
michael@0 88 #define TELEMETRY_ENABLED "toolkit.telemetry.enabled"
michael@0 89 #define ALLOW_EXPERIMENTS "network.allow-experiments"
michael@0 90 #define SAFE_HINT_HEADER_VALUE "safeHint.enabled"
michael@0 91
michael@0 92 #define UA_PREF(_pref) UA_PREF_PREFIX _pref
michael@0 93 #define HTTP_PREF(_pref) HTTP_PREF_PREFIX _pref
michael@0 94 #define BROWSER_PREF(_pref) BROWSER_PREF_PREFIX _pref
michael@0 95
michael@0 96 #define NS_HTTP_PROTOCOL_FLAGS (URI_STD | ALLOWS_PROXY | ALLOWS_PROXY_HTTP | URI_LOADABLE_BY_ANYONE)
michael@0 97
michael@0 98 //-----------------------------------------------------------------------------
michael@0 99
michael@0 100 namespace mozilla {
michael@0 101 namespace net {
michael@0 102
michael@0 103 static nsresult
michael@0 104 NewURI(const nsACString &aSpec,
michael@0 105 const char *aCharset,
michael@0 106 nsIURI *aBaseURI,
michael@0 107 int32_t aDefaultPort,
michael@0 108 nsIURI **aURI)
michael@0 109 {
michael@0 110 nsStandardURL *url = new nsStandardURL();
michael@0 111 if (!url)
michael@0 112 return NS_ERROR_OUT_OF_MEMORY;
michael@0 113 NS_ADDREF(url);
michael@0 114
michael@0 115 nsresult rv = url->Init(nsIStandardURL::URLTYPE_AUTHORITY,
michael@0 116 aDefaultPort, aSpec, aCharset, aBaseURI);
michael@0 117 if (NS_FAILED(rv)) {
michael@0 118 NS_RELEASE(url);
michael@0 119 return rv;
michael@0 120 }
michael@0 121
michael@0 122 *aURI = url; // no QI needed
michael@0 123 return NS_OK;
michael@0 124 }
michael@0 125
michael@0 126 //-----------------------------------------------------------------------------
michael@0 127 // nsHttpHandler <public>
michael@0 128 //-----------------------------------------------------------------------------
michael@0 129
michael@0 130 nsHttpHandler *gHttpHandler = nullptr;
michael@0 131
michael@0 132 nsHttpHandler::nsHttpHandler()
michael@0 133 : mConnMgr(nullptr)
michael@0 134 , mHttpVersion(NS_HTTP_VERSION_1_1)
michael@0 135 , mProxyHttpVersion(NS_HTTP_VERSION_1_1)
michael@0 136 , mCapabilities(NS_HTTP_ALLOW_KEEPALIVE)
michael@0 137 , mReferrerLevel(0xff) // by default we always send a referrer
michael@0 138 , mSpoofReferrerSource(false)
michael@0 139 , mReferrerTrimmingPolicy(0)
michael@0 140 , mReferrerXOriginPolicy(0)
michael@0 141 , mFastFallbackToIPv4(false)
michael@0 142 , mProxyPipelining(true)
michael@0 143 , mIdleTimeout(PR_SecondsToInterval(10))
michael@0 144 , mSpdyTimeout(PR_SecondsToInterval(180))
michael@0 145 , mResponseTimeout(300)
michael@0 146 , mResponseTimeoutEnabled(false)
michael@0 147 , mMaxRequestAttempts(10)
michael@0 148 , mMaxRequestDelay(10)
michael@0 149 , mIdleSynTimeout(250)
michael@0 150 , mPipeliningEnabled(false)
michael@0 151 , mMaxConnections(24)
michael@0 152 , mMaxPersistentConnectionsPerServer(2)
michael@0 153 , mMaxPersistentConnectionsPerProxy(4)
michael@0 154 , mMaxPipelinedRequests(32)
michael@0 155 , mMaxOptimisticPipelinedRequests(4)
michael@0 156 , mPipelineAggressive(false)
michael@0 157 , mMaxPipelineObjectSize(300000)
michael@0 158 , mPipelineRescheduleOnTimeout(true)
michael@0 159 , mPipelineRescheduleTimeout(PR_MillisecondsToInterval(1500))
michael@0 160 , mPipelineReadTimeout(PR_MillisecondsToInterval(30000))
michael@0 161 , mRedirectionLimit(10)
michael@0 162 , mPhishyUserPassLength(1)
michael@0 163 , mQoSBits(0x00)
michael@0 164 , mPipeliningOverSSL(false)
michael@0 165 , mEnforceAssocReq(false)
michael@0 166 , mLastUniqueID(NowInSeconds())
michael@0 167 , mSessionStartTime(0)
michael@0 168 , mLegacyAppName("Mozilla")
michael@0 169 , mLegacyAppVersion("5.0")
michael@0 170 , mProduct("Gecko")
michael@0 171 , mUserAgentIsDirty(true)
michael@0 172 , mUseCache(true)
michael@0 173 , mPromptTempRedirect(true)
michael@0 174 , mSendSecureXSiteReferrer(true)
michael@0 175 , mEnablePersistentHttpsCaching(false)
michael@0 176 , mDoNotTrackEnabled(false)
michael@0 177 , mDoNotTrackValue(1)
michael@0 178 , mSafeHintEnabled(false)
michael@0 179 , mParentalControlEnabled(false)
michael@0 180 , mTelemetryEnabled(false)
michael@0 181 , mAllowExperiments(true)
michael@0 182 , mHandlerActive(false)
michael@0 183 , mEnableSpdy(false)
michael@0 184 , mSpdyV3(true)
michael@0 185 , mSpdyV31(true)
michael@0 186 , mHttp2DraftEnabled(true)
michael@0 187 , mEnforceHttp2TlsProfile(true)
michael@0 188 , mCoalesceSpdy(true)
michael@0 189 , mSpdyPersistentSettings(false)
michael@0 190 , mAllowPush(true)
michael@0 191 , mSpdySendingChunkSize(ASpdySession::kSendingChunkSize)
michael@0 192 , mSpdySendBufferSize(ASpdySession::kTCPSendBufferSize)
michael@0 193 , mSpdyPushAllowance(32768)
michael@0 194 , mSpdyPingThreshold(PR_SecondsToInterval(58))
michael@0 195 , mSpdyPingTimeout(PR_SecondsToInterval(8))
michael@0 196 , mConnectTimeout(90000)
michael@0 197 , mBypassCacheLockThreshold(250.0)
michael@0 198 , mParallelSpeculativeConnectLimit(6)
michael@0 199 , mRequestTokenBucketEnabled(true)
michael@0 200 , mRequestTokenBucketMinParallelism(6)
michael@0 201 , mRequestTokenBucketHz(100)
michael@0 202 , mRequestTokenBucketBurst(32)
michael@0 203 , mTCPKeepaliveShortLivedEnabled(false)
michael@0 204 , mTCPKeepaliveShortLivedTimeS(60)
michael@0 205 , mTCPKeepaliveShortLivedIdleTimeS(10)
michael@0 206 , mTCPKeepaliveLongLivedEnabled(false)
michael@0 207 , mTCPKeepaliveLongLivedIdleTimeS(600)
michael@0 208 {
michael@0 209 #if defined(PR_LOGGING)
michael@0 210 gHttpLog = PR_NewLogModule("nsHttp");
michael@0 211 #endif
michael@0 212
michael@0 213 LOG(("Creating nsHttpHandler [this=%p].\n", this));
michael@0 214
michael@0 215 RegisterStrongMemoryReporter(new SpdyZlibReporter());
michael@0 216
michael@0 217 MOZ_ASSERT(!gHttpHandler, "HTTP handler already created!");
michael@0 218 gHttpHandler = this;
michael@0 219 }
michael@0 220
michael@0 221 nsHttpHandler::~nsHttpHandler()
michael@0 222 {
michael@0 223 LOG(("Deleting nsHttpHandler [this=%p]\n", this));
michael@0 224
michael@0 225 // make sure the connection manager is shutdown
michael@0 226 if (mConnMgr) {
michael@0 227 mConnMgr->Shutdown();
michael@0 228 NS_RELEASE(mConnMgr);
michael@0 229 }
michael@0 230
michael@0 231 // Note: don't call NeckoChild::DestroyNeckoChild() here, as it's too late
michael@0 232 // and it'll segfault. NeckoChild will get cleaned up by process exit.
michael@0 233
michael@0 234 nsHttp::DestroyAtomTable();
michael@0 235 if (mPipelineTestTimer) {
michael@0 236 mPipelineTestTimer->Cancel();
michael@0 237 mPipelineTestTimer = nullptr;
michael@0 238 }
michael@0 239
michael@0 240 gHttpHandler = nullptr;
michael@0 241 }
michael@0 242
michael@0 243 nsresult
michael@0 244 nsHttpHandler::Init()
michael@0 245 {
michael@0 246 nsresult rv;
michael@0 247
michael@0 248 LOG(("nsHttpHandler::Init\n"));
michael@0 249
michael@0 250 rv = nsHttp::CreateAtomTable();
michael@0 251 if (NS_FAILED(rv))
michael@0 252 return rv;
michael@0 253
michael@0 254 nsCOMPtr<nsIIOService> service = do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
michael@0 255 if (NS_FAILED(rv)) {
michael@0 256 NS_WARNING("unable to continue without io service");
michael@0 257 return rv;
michael@0 258 }
michael@0 259 mIOService = new nsMainThreadPtrHolder<nsIIOService>(service);
michael@0 260
michael@0 261 if (IsNeckoChild())
michael@0 262 NeckoChild::InitNeckoChild();
michael@0 263
michael@0 264 InitUserAgentComponents();
michael@0 265
michael@0 266 // monitor some preference changes
michael@0 267 nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID);
michael@0 268 if (prefBranch) {
michael@0 269 prefBranch->AddObserver(HTTP_PREF_PREFIX, this, true);
michael@0 270 prefBranch->AddObserver(UA_PREF_PREFIX, this, true);
michael@0 271 prefBranch->AddObserver(INTL_ACCEPT_LANGUAGES, this, true);
michael@0 272 prefBranch->AddObserver(BROWSER_PREF("disk_cache_ssl"), this, true);
michael@0 273 prefBranch->AddObserver(DONOTTRACK_HEADER_ENABLED, this, true);
michael@0 274 prefBranch->AddObserver(DONOTTRACK_HEADER_VALUE, this, true);
michael@0 275 prefBranch->AddObserver(TELEMETRY_ENABLED, this, true);
michael@0 276 prefBranch->AddObserver(HTTP_PREF("tcp_keepalive.short_lived_connections"), this, true);
michael@0 277 prefBranch->AddObserver(HTTP_PREF("tcp_keepalive.long_lived_connections"), this, true);
michael@0 278 prefBranch->AddObserver(SAFE_HINT_HEADER_VALUE, this, true);
michael@0 279 PrefsChanged(prefBranch, nullptr);
michael@0 280 }
michael@0 281
michael@0 282 mMisc.AssignLiteral("rv:" MOZILLA_UAVERSION);
michael@0 283
michael@0 284 mCompatFirefox.AssignLiteral("Firefox/" MOZILLA_UAVERSION);
michael@0 285
michael@0 286 nsCOMPtr<nsIXULAppInfo> appInfo =
michael@0 287 do_GetService("@mozilla.org/xre/app-info;1");
michael@0 288
michael@0 289 mAppName.AssignLiteral(MOZ_APP_UA_NAME);
michael@0 290 if (mAppName.Length() == 0 && appInfo) {
michael@0 291 // Try to get the UA name from appInfo, falling back to the name
michael@0 292 appInfo->GetUAName(mAppName);
michael@0 293 if (mAppName.Length() == 0) {
michael@0 294 appInfo->GetName(mAppName);
michael@0 295 }
michael@0 296 appInfo->GetVersion(mAppVersion);
michael@0 297 mAppName.StripChars(" ()<>@,;:\\\"/[]?={}");
michael@0 298 } else {
michael@0 299 mAppVersion.AssignLiteral(MOZ_APP_UA_VERSION);
michael@0 300 }
michael@0 301
michael@0 302 mSessionStartTime = NowInSeconds();
michael@0 303 mHandlerActive = true;
michael@0 304
michael@0 305 rv = mAuthCache.Init();
michael@0 306 if (NS_FAILED(rv)) return rv;
michael@0 307
michael@0 308 rv = mPrivateAuthCache.Init();
michael@0 309 if (NS_FAILED(rv)) return rv;
michael@0 310
michael@0 311 rv = InitConnectionMgr();
michael@0 312 if (NS_FAILED(rv)) return rv;
michael@0 313
michael@0 314 #ifdef ANDROID
michael@0 315 mProductSub.AssignLiteral(MOZILLA_UAVERSION);
michael@0 316 #else
michael@0 317 mProductSub.AssignLiteral("20100101");
michael@0 318 #endif
michael@0 319
michael@0 320 #if DEBUG
michael@0 321 // dump user agent prefs
michael@0 322 LOG(("> legacy-app-name = %s\n", mLegacyAppName.get()));
michael@0 323 LOG(("> legacy-app-version = %s\n", mLegacyAppVersion.get()));
michael@0 324 LOG(("> platform = %s\n", mPlatform.get()));
michael@0 325 LOG(("> oscpu = %s\n", mOscpu.get()));
michael@0 326 LOG(("> misc = %s\n", mMisc.get()));
michael@0 327 LOG(("> product = %s\n", mProduct.get()));
michael@0 328 LOG(("> product-sub = %s\n", mProductSub.get()));
michael@0 329 LOG(("> app-name = %s\n", mAppName.get()));
michael@0 330 LOG(("> app-version = %s\n", mAppVersion.get()));
michael@0 331 LOG(("> compat-firefox = %s\n", mCompatFirefox.get()));
michael@0 332 LOG(("> user-agent = %s\n", UserAgent().get()));
michael@0 333 #endif
michael@0 334
michael@0 335 // Startup the http category
michael@0 336 // Bring alive the objects in the http-protocol-startup category
michael@0 337 NS_CreateServicesFromCategory(NS_HTTP_STARTUP_CATEGORY,
michael@0 338 static_cast<nsISupports*>(static_cast<void*>(this)),
michael@0 339 NS_HTTP_STARTUP_TOPIC);
michael@0 340
michael@0 341 nsCOMPtr<nsIObserverService> obsService = services::GetObserverService();
michael@0 342 mObserverService = new nsMainThreadPtrHolder<nsIObserverService>(obsService);
michael@0 343 if (mObserverService) {
michael@0 344 mObserverService->AddObserver(this, "profile-change-net-teardown", true);
michael@0 345 mObserverService->AddObserver(this, "profile-change-net-restore", true);
michael@0 346 mObserverService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, true);
michael@0 347 mObserverService->AddObserver(this, "net:clear-active-logins", true);
michael@0 348 mObserverService->AddObserver(this, "net:prune-dead-connections", true);
michael@0 349 mObserverService->AddObserver(this, "net:prune-all-connections", true);
michael@0 350 mObserverService->AddObserver(this, "net:failed-to-process-uri-content", true);
michael@0 351 mObserverService->AddObserver(this, "last-pb-context-exited", true);
michael@0 352 }
michael@0 353
michael@0 354 MakeNewRequestTokenBucket();
michael@0 355 mWifiTickler = new Tickler();
michael@0 356 if (NS_FAILED(mWifiTickler->Init()))
michael@0 357 mWifiTickler = nullptr;
michael@0 358
michael@0 359 nsCOMPtr<nsIParentalControlsService> pc = do_CreateInstance("@mozilla.org/parental-controls-service;1");
michael@0 360 if (pc) {
michael@0 361 pc->GetParentalControlsEnabled(&mParentalControlEnabled);
michael@0 362 }
michael@0 363 return NS_OK;
michael@0 364 }
michael@0 365
michael@0 366 void
michael@0 367 nsHttpHandler::MakeNewRequestTokenBucket()
michael@0 368 {
michael@0 369 if (!mConnMgr)
michael@0 370 return;
michael@0 371
michael@0 372 nsRefPtr<EventTokenBucket> tokenBucket =
michael@0 373 new EventTokenBucket(RequestTokenBucketHz(),
michael@0 374 RequestTokenBucketBurst());
michael@0 375 mConnMgr->UpdateRequestTokenBucket(tokenBucket);
michael@0 376 }
michael@0 377
michael@0 378 nsresult
michael@0 379 nsHttpHandler::InitConnectionMgr()
michael@0 380 {
michael@0 381 nsresult rv;
michael@0 382
michael@0 383 if (!mConnMgr) {
michael@0 384 mConnMgr = new nsHttpConnectionMgr();
michael@0 385 if (!mConnMgr)
michael@0 386 return NS_ERROR_OUT_OF_MEMORY;
michael@0 387 NS_ADDREF(mConnMgr);
michael@0 388 }
michael@0 389
michael@0 390 rv = mConnMgr->Init(mMaxConnections,
michael@0 391 mMaxPersistentConnectionsPerServer,
michael@0 392 mMaxPersistentConnectionsPerProxy,
michael@0 393 mMaxRequestDelay,
michael@0 394 mMaxPipelinedRequests,
michael@0 395 mMaxOptimisticPipelinedRequests);
michael@0 396 return rv;
michael@0 397 }
michael@0 398
michael@0 399 nsresult
michael@0 400 nsHttpHandler::AddStandardRequestHeaders(nsHttpHeaderArray *request)
michael@0 401 {
michael@0 402 nsresult rv;
michael@0 403
michael@0 404 // Add the "User-Agent" header
michael@0 405 rv = request->SetHeader(nsHttp::User_Agent, UserAgent());
michael@0 406 if (NS_FAILED(rv)) return rv;
michael@0 407
michael@0 408 // MIME based content negotiation lives!
michael@0 409 // Add the "Accept" header
michael@0 410 rv = request->SetHeader(nsHttp::Accept, mAccept);
michael@0 411 if (NS_FAILED(rv)) return rv;
michael@0 412
michael@0 413 // Add the "Accept-Language" header
michael@0 414 if (!mAcceptLanguages.IsEmpty()) {
michael@0 415 // Add the "Accept-Language" header
michael@0 416 rv = request->SetHeader(nsHttp::Accept_Language, mAcceptLanguages);
michael@0 417 if (NS_FAILED(rv)) return rv;
michael@0 418 }
michael@0 419
michael@0 420 // Add the "Accept-Encoding" header
michael@0 421 rv = request->SetHeader(nsHttp::Accept_Encoding, mAcceptEncodings);
michael@0 422 if (NS_FAILED(rv)) return rv;
michael@0 423
michael@0 424 // Add the "Do-Not-Track" header
michael@0 425 if (mDoNotTrackEnabled) {
michael@0 426 rv = request->SetHeader(nsHttp::DoNotTrack,
michael@0 427 nsPrintfCString("%d", mDoNotTrackValue));
michael@0 428 if (NS_FAILED(rv)) return rv;
michael@0 429 }
michael@0 430
michael@0 431 // add the "Send Hint" header
michael@0 432 if (mSafeHintEnabled || mParentalControlEnabled) {
michael@0 433 rv = request->SetHeader(nsHttp::Prefer, NS_LITERAL_CSTRING("safe"));
michael@0 434 if (NS_FAILED(rv)) return rv;
michael@0 435 }
michael@0 436 return NS_OK;
michael@0 437 }
michael@0 438
michael@0 439 nsresult
michael@0 440 nsHttpHandler::AddConnectionHeader(nsHttpHeaderArray *request,
michael@0 441 uint32_t caps)
michael@0 442 {
michael@0 443 // RFC2616 section 19.6.2 states that the "Connection: keep-alive"
michael@0 444 // and "Keep-alive" request headers should not be sent by HTTP/1.1
michael@0 445 // user-agents. But this is not a problem in practice, and the
michael@0 446 // alternative proxy-connection is worse. see 570283
michael@0 447
michael@0 448 NS_NAMED_LITERAL_CSTRING(close, "close");
michael@0 449 NS_NAMED_LITERAL_CSTRING(keepAlive, "keep-alive");
michael@0 450
michael@0 451 const nsACString *connectionType = &close;
michael@0 452 if (caps & NS_HTTP_ALLOW_KEEPALIVE) {
michael@0 453 connectionType = &keepAlive;
michael@0 454 }
michael@0 455
michael@0 456 return request->SetHeader(nsHttp::Connection, *connectionType);
michael@0 457 }
michael@0 458
michael@0 459 bool
michael@0 460 nsHttpHandler::IsAcceptableEncoding(const char *enc)
michael@0 461 {
michael@0 462 if (!enc)
michael@0 463 return false;
michael@0 464
michael@0 465 // HTTP 1.1 allows servers to send x-gzip and x-compress instead
michael@0 466 // of gzip and compress, for example. So, we'll always strip off
michael@0 467 // an "x-" prefix before matching the encoding to one we claim
michael@0 468 // to accept.
michael@0 469 if (!PL_strncasecmp(enc, "x-", 2))
michael@0 470 enc += 2;
michael@0 471
michael@0 472 // gzip and deflate are inherently acceptable in modern HTTP - always
michael@0 473 // process them if a stream converter can also be found.
michael@0 474 if (!PL_strcasecmp(enc, "gzip") || !PL_strcasecmp(enc, "deflate"))
michael@0 475 return true;
michael@0 476
michael@0 477 return nsHttp::FindToken(mAcceptEncodings.get(), enc, HTTP_LWS ",") != nullptr;
michael@0 478 }
michael@0 479
michael@0 480 nsresult
michael@0 481 nsHttpHandler::GetStreamConverterService(nsIStreamConverterService **result)
michael@0 482 {
michael@0 483 if (!mStreamConvSvc) {
michael@0 484 nsresult rv;
michael@0 485 nsCOMPtr<nsIStreamConverterService> service =
michael@0 486 do_GetService(NS_STREAMCONVERTERSERVICE_CONTRACTID, &rv);
michael@0 487 if (NS_FAILED(rv))
michael@0 488 return rv;
michael@0 489 mStreamConvSvc = new nsMainThreadPtrHolder<nsIStreamConverterService>(service);
michael@0 490 }
michael@0 491 *result = mStreamConvSvc;
michael@0 492 NS_ADDREF(*result);
michael@0 493 return NS_OK;
michael@0 494 }
michael@0 495
michael@0 496 nsISiteSecurityService*
michael@0 497 nsHttpHandler::GetSSService()
michael@0 498 {
michael@0 499 if (!mSSService) {
michael@0 500 nsCOMPtr<nsISiteSecurityService> service = do_GetService(NS_SSSERVICE_CONTRACTID);
michael@0 501 mSSService = new nsMainThreadPtrHolder<nsISiteSecurityService>(service);
michael@0 502 }
michael@0 503 return mSSService;
michael@0 504 }
michael@0 505
michael@0 506 nsICookieService *
michael@0 507 nsHttpHandler::GetCookieService()
michael@0 508 {
michael@0 509 if (!mCookieService) {
michael@0 510 nsCOMPtr<nsICookieService> service = do_GetService(NS_COOKIESERVICE_CONTRACTID);
michael@0 511 mCookieService = new nsMainThreadPtrHolder<nsICookieService>(service);
michael@0 512 }
michael@0 513 return mCookieService;
michael@0 514 }
michael@0 515
michael@0 516 nsresult
michael@0 517 nsHttpHandler::GetIOService(nsIIOService** result)
michael@0 518 {
michael@0 519 NS_ADDREF(*result = mIOService);
michael@0 520 return NS_OK;
michael@0 521 }
michael@0 522
michael@0 523 uint32_t
michael@0 524 nsHttpHandler::Get32BitsOfPseudoRandom()
michael@0 525 {
michael@0 526 // only confirm rand seeding on socket thread
michael@0 527 MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
michael@0 528
michael@0 529 // rand() provides different amounts of PRNG on different platforms.
michael@0 530 // 15 or 31 bits are common amounts.
michael@0 531
michael@0 532 PR_STATIC_ASSERT(RAND_MAX >= 0xfff);
michael@0 533
michael@0 534 #if RAND_MAX < 0xffffU
michael@0 535 return ((uint16_t) rand() << 20) |
michael@0 536 (((uint16_t) rand() & 0xfff) << 8) |
michael@0 537 ((uint16_t) rand() & 0xff);
michael@0 538 #elif RAND_MAX < 0xffffffffU
michael@0 539 return ((uint16_t) rand() << 16) | ((uint16_t) rand() & 0xffff);
michael@0 540 #else
michael@0 541 return (uint32_t) rand();
michael@0 542 #endif
michael@0 543 }
michael@0 544
michael@0 545 void
michael@0 546 nsHttpHandler::NotifyObservers(nsIHttpChannel *chan, const char *event)
michael@0 547 {
michael@0 548 LOG(("nsHttpHandler::NotifyObservers [chan=%x event=\"%s\"]\n", chan, event));
michael@0 549 if (mObserverService)
michael@0 550 mObserverService->NotifyObservers(chan, event, nullptr);
michael@0 551 }
michael@0 552
michael@0 553 nsresult
michael@0 554 nsHttpHandler::AsyncOnChannelRedirect(nsIChannel* oldChan, nsIChannel* newChan,
michael@0 555 uint32_t flags)
michael@0 556 {
michael@0 557 // TODO E10S This helper has to be initialized on the other process
michael@0 558 nsRefPtr<nsAsyncRedirectVerifyHelper> redirectCallbackHelper =
michael@0 559 new nsAsyncRedirectVerifyHelper();
michael@0 560
michael@0 561 return redirectCallbackHelper->Init(oldChan, newChan, flags);
michael@0 562 }
michael@0 563
michael@0 564 /* static */ nsresult
michael@0 565 nsHttpHandler::GenerateHostPort(const nsCString& host, int32_t port,
michael@0 566 nsCString& hostLine)
michael@0 567 {
michael@0 568 return NS_GenerateHostPort(host, port, hostLine);
michael@0 569 }
michael@0 570
michael@0 571 //-----------------------------------------------------------------------------
michael@0 572 // nsHttpHandler <private>
michael@0 573 //-----------------------------------------------------------------------------
michael@0 574
michael@0 575 const nsAFlatCString &
michael@0 576 nsHttpHandler::UserAgent()
michael@0 577 {
michael@0 578 if (mUserAgentOverride) {
michael@0 579 LOG(("using general.useragent.override : %s\n", mUserAgentOverride.get()));
michael@0 580 return mUserAgentOverride;
michael@0 581 }
michael@0 582
michael@0 583 if (mUserAgentIsDirty) {
michael@0 584 BuildUserAgent();
michael@0 585 mUserAgentIsDirty = false;
michael@0 586 }
michael@0 587
michael@0 588 return mUserAgent;
michael@0 589 }
michael@0 590
michael@0 591 void
michael@0 592 nsHttpHandler::BuildUserAgent()
michael@0 593 {
michael@0 594 LOG(("nsHttpHandler::BuildUserAgent\n"));
michael@0 595
michael@0 596 MOZ_ASSERT(!mLegacyAppName.IsEmpty() &&
michael@0 597 !mLegacyAppVersion.IsEmpty(),
michael@0 598 "HTTP cannot send practical requests without this much");
michael@0 599
michael@0 600 // preallocate to worst-case size, which should always be better
michael@0 601 // than if we didn't preallocate at all.
michael@0 602 mUserAgent.SetCapacity(mLegacyAppName.Length() +
michael@0 603 mLegacyAppVersion.Length() +
michael@0 604 #ifndef UA_SPARE_PLATFORM
michael@0 605 mPlatform.Length() +
michael@0 606 #endif
michael@0 607 mOscpu.Length() +
michael@0 608 mMisc.Length() +
michael@0 609 mProduct.Length() +
michael@0 610 mProductSub.Length() +
michael@0 611 mAppName.Length() +
michael@0 612 mAppVersion.Length() +
michael@0 613 mCompatFirefox.Length() +
michael@0 614 mCompatDevice.Length() +
michael@0 615 13);
michael@0 616
michael@0 617 // Application portion
michael@0 618 mUserAgent.Assign(mLegacyAppName);
michael@0 619 mUserAgent += '/';
michael@0 620 mUserAgent += mLegacyAppVersion;
michael@0 621 mUserAgent += ' ';
michael@0 622
michael@0 623 // Application comment
michael@0 624 mUserAgent += '(';
michael@0 625 #ifndef UA_SPARE_PLATFORM
michael@0 626 if (!mPlatform.IsEmpty()) {
michael@0 627 mUserAgent += mPlatform;
michael@0 628 mUserAgent.AppendLiteral("; ");
michael@0 629 }
michael@0 630 #endif
michael@0 631 if (!mCompatDevice.IsEmpty()) {
michael@0 632 mUserAgent += mCompatDevice;
michael@0 633 mUserAgent.AppendLiteral("; ");
michael@0 634 }
michael@0 635 else if (!mOscpu.IsEmpty()) {
michael@0 636 mUserAgent += mOscpu;
michael@0 637 mUserAgent.AppendLiteral("; ");
michael@0 638 }
michael@0 639 mUserAgent += mMisc;
michael@0 640 mUserAgent += ')';
michael@0 641
michael@0 642 // Product portion
michael@0 643 mUserAgent += ' ';
michael@0 644 mUserAgent += mProduct;
michael@0 645 mUserAgent += '/';
michael@0 646 mUserAgent += mProductSub;
michael@0 647
michael@0 648 bool isFirefox = mAppName.EqualsLiteral("Firefox");
michael@0 649 if (isFirefox || mCompatFirefoxEnabled) {
michael@0 650 // "Firefox/x.y" (compatibility) app token
michael@0 651 mUserAgent += ' ';
michael@0 652 mUserAgent += mCompatFirefox;
michael@0 653 }
michael@0 654 if (!isFirefox) {
michael@0 655 // App portion
michael@0 656 mUserAgent += ' ';
michael@0 657 mUserAgent += mAppName;
michael@0 658 mUserAgent += '/';
michael@0 659 mUserAgent += mAppVersion;
michael@0 660 }
michael@0 661 }
michael@0 662
michael@0 663 #ifdef XP_WIN
michael@0 664 #define WNT_BASE "Windows NT %ld.%ld"
michael@0 665 #define W64_PREFIX "; Win64"
michael@0 666 #endif
michael@0 667
michael@0 668 void
michael@0 669 nsHttpHandler::InitUserAgentComponents()
michael@0 670 {
michael@0 671 #ifndef MOZ_UA_OS_AGNOSTIC
michael@0 672 // Gather platform.
michael@0 673 mPlatform.AssignLiteral(
michael@0 674 #if defined(ANDROID)
michael@0 675 "Android"
michael@0 676 #elif defined(XP_WIN)
michael@0 677 "Windows"
michael@0 678 #elif defined(XP_MACOSX)
michael@0 679 "Macintosh"
michael@0 680 #elif defined(MOZ_X11)
michael@0 681 "X11"
michael@0 682 #endif
michael@0 683 );
michael@0 684 #endif
michael@0 685
michael@0 686 #if defined(ANDROID) || defined(MOZ_B2G)
michael@0 687 nsCOMPtr<nsIPropertyBag2> infoService = do_GetService("@mozilla.org/system-info;1");
michael@0 688 MOZ_ASSERT(infoService, "Could not find a system info service");
michael@0 689
michael@0 690 bool isTablet;
michael@0 691 nsresult rv = infoService->GetPropertyAsBool(NS_LITERAL_STRING("tablet"), &isTablet);
michael@0 692 if (NS_SUCCEEDED(rv) && isTablet)
michael@0 693 mCompatDevice.AssignLiteral("Tablet");
michael@0 694 else
michael@0 695 mCompatDevice.AssignLiteral("Mobile");
michael@0 696 #endif
michael@0 697
michael@0 698 #ifndef MOZ_UA_OS_AGNOSTIC
michael@0 699 // Gather OS/CPU.
michael@0 700 #if defined(XP_WIN)
michael@0 701 OSVERSIONINFO info = { sizeof(OSVERSIONINFO) };
michael@0 702 #pragma warning(push)
michael@0 703 #pragma warning(disable:4996)
michael@0 704 if (GetVersionEx(&info)) {
michael@0 705 #pragma warning(pop)
michael@0 706 const char *format;
michael@0 707 #if defined _M_IA64
michael@0 708 format = WNT_BASE W64_PREFIX "; IA64";
michael@0 709 #elif defined _M_X64 || defined _M_AMD64
michael@0 710 format = WNT_BASE W64_PREFIX "; x64";
michael@0 711 #else
michael@0 712 BOOL isWow64 = FALSE;
michael@0 713 if (!IsWow64Process(GetCurrentProcess(), &isWow64)) {
michael@0 714 isWow64 = FALSE;
michael@0 715 }
michael@0 716 format = isWow64
michael@0 717 ? WNT_BASE "; WOW64"
michael@0 718 : WNT_BASE;
michael@0 719 #endif
michael@0 720 char *buf = PR_smprintf(format,
michael@0 721 info.dwMajorVersion,
michael@0 722 info.dwMinorVersion);
michael@0 723 if (buf) {
michael@0 724 mOscpu = buf;
michael@0 725 PR_smprintf_free(buf);
michael@0 726 }
michael@0 727 }
michael@0 728 #elif defined (XP_MACOSX)
michael@0 729 #if defined(__ppc__)
michael@0 730 mOscpu.AssignLiteral("PPC Mac OS X");
michael@0 731 #elif defined(__i386__) || defined(__x86_64__)
michael@0 732 mOscpu.AssignLiteral("Intel Mac OS X");
michael@0 733 #endif
michael@0 734 SInt32 majorVersion = nsCocoaFeatures::OSXVersionMajor();
michael@0 735 SInt32 minorVersion = nsCocoaFeatures::OSXVersionMinor();
michael@0 736 mOscpu += nsPrintfCString(" %d.%d", majorVersion, minorVersion);
michael@0 737 #elif defined (XP_UNIX)
michael@0 738 struct utsname name;
michael@0 739
michael@0 740 int ret = uname(&name);
michael@0 741 if (ret >= 0) {
michael@0 742 nsAutoCString buf;
michael@0 743 buf = (char*)name.sysname;
michael@0 744
michael@0 745 if (strcmp(name.machine, "x86_64") == 0 &&
michael@0 746 sizeof(void *) == sizeof(int32_t)) {
michael@0 747 // We're running 32-bit code on x86_64. Make this browser
michael@0 748 // look like it's running on i686 hardware, but append "
michael@0 749 // (x86_64)" to the end of the oscpu identifier to be able
michael@0 750 // to differentiate this from someone running 64-bit code
michael@0 751 // on x86_64..
michael@0 752
michael@0 753 buf += " i686 on x86_64";
michael@0 754 } else {
michael@0 755 buf += ' ';
michael@0 756
michael@0 757 #ifdef AIX
michael@0 758 // AIX uname returns machine specific info in the uname.machine
michael@0 759 // field and does not return the cpu type like other platforms.
michael@0 760 // We use the AIX version and release numbers instead.
michael@0 761 buf += (char*)name.version;
michael@0 762 buf += '.';
michael@0 763 buf += (char*)name.release;
michael@0 764 #else
michael@0 765 buf += (char*)name.machine;
michael@0 766 #endif
michael@0 767 }
michael@0 768
michael@0 769 mOscpu.Assign(buf);
michael@0 770 }
michael@0 771 #endif
michael@0 772 #endif
michael@0 773
michael@0 774 mUserAgentIsDirty = true;
michael@0 775 }
michael@0 776
michael@0 777 uint32_t
michael@0 778 nsHttpHandler::MaxSocketCount()
michael@0 779 {
michael@0 780 PR_CallOnce(&nsSocketTransportService::gMaxCountInitOnce,
michael@0 781 nsSocketTransportService::DiscoverMaxCount);
michael@0 782 // Don't use the full max count because sockets can be held in
michael@0 783 // the persistent connection pool for a long time and that could
michael@0 784 // starve other users.
michael@0 785
michael@0 786 uint32_t maxCount = nsSocketTransportService::gMaxCount;
michael@0 787 if (maxCount <= 8)
michael@0 788 maxCount = 1;
michael@0 789 else
michael@0 790 maxCount -= 8;
michael@0 791
michael@0 792 return maxCount;
michael@0 793 }
michael@0 794
michael@0 795 void
michael@0 796 nsHttpHandler::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
michael@0 797 {
michael@0 798 nsresult rv = NS_OK;
michael@0 799 int32_t val;
michael@0 800
michael@0 801 LOG(("nsHttpHandler::PrefsChanged [pref=%s]\n", pref));
michael@0 802
michael@0 803 #define PREF_CHANGED(p) ((pref == nullptr) || !PL_strcmp(pref, p))
michael@0 804 #define MULTI_PREF_CHANGED(p) \
michael@0 805 ((pref == nullptr) || !PL_strncmp(pref, p, sizeof(p) - 1))
michael@0 806
michael@0 807 //
michael@0 808 // UA components
michael@0 809 //
michael@0 810
michael@0 811 bool cVar = false;
michael@0 812
michael@0 813 if (PREF_CHANGED(UA_PREF("compatMode.firefox"))) {
michael@0 814 rv = prefs->GetBoolPref(UA_PREF("compatMode.firefox"), &cVar);
michael@0 815 mCompatFirefoxEnabled = (NS_SUCCEEDED(rv) && cVar);
michael@0 816 mUserAgentIsDirty = true;
michael@0 817 }
michael@0 818
michael@0 819 // general.useragent.override
michael@0 820 if (PREF_CHANGED(UA_PREF("override"))) {
michael@0 821 prefs->GetCharPref(UA_PREF("override"),
michael@0 822 getter_Copies(mUserAgentOverride));
michael@0 823 mUserAgentIsDirty = true;
michael@0 824 }
michael@0 825
michael@0 826 //
michael@0 827 // HTTP options
michael@0 828 //
michael@0 829
michael@0 830 if (PREF_CHANGED(HTTP_PREF("keep-alive.timeout"))) {
michael@0 831 rv = prefs->GetIntPref(HTTP_PREF("keep-alive.timeout"), &val);
michael@0 832 if (NS_SUCCEEDED(rv))
michael@0 833 mIdleTimeout = PR_SecondsToInterval(clamped(val, 1, 0xffff));
michael@0 834 }
michael@0 835
michael@0 836 if (PREF_CHANGED(HTTP_PREF("request.max-attempts"))) {
michael@0 837 rv = prefs->GetIntPref(HTTP_PREF("request.max-attempts"), &val);
michael@0 838 if (NS_SUCCEEDED(rv))
michael@0 839 mMaxRequestAttempts = (uint16_t) clamped(val, 1, 0xffff);
michael@0 840 }
michael@0 841
michael@0 842 if (PREF_CHANGED(HTTP_PREF("request.max-start-delay"))) {
michael@0 843 rv = prefs->GetIntPref(HTTP_PREF("request.max-start-delay"), &val);
michael@0 844 if (NS_SUCCEEDED(rv)) {
michael@0 845 mMaxRequestDelay = (uint16_t) clamped(val, 0, 0xffff);
michael@0 846 if (mConnMgr)
michael@0 847 mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_REQUEST_DELAY,
michael@0 848 mMaxRequestDelay);
michael@0 849 }
michael@0 850 }
michael@0 851
michael@0 852 if (PREF_CHANGED(HTTP_PREF("response.timeout"))) {
michael@0 853 rv = prefs->GetIntPref(HTTP_PREF("response.timeout"), &val);
michael@0 854 if (NS_SUCCEEDED(rv))
michael@0 855 mResponseTimeout = PR_SecondsToInterval(clamped(val, 0, 0xffff));
michael@0 856 }
michael@0 857
michael@0 858 if (PREF_CHANGED(HTTP_PREF("max-connections"))) {
michael@0 859 rv = prefs->GetIntPref(HTTP_PREF("max-connections"), &val);
michael@0 860 if (NS_SUCCEEDED(rv)) {
michael@0 861
michael@0 862 mMaxConnections = (uint16_t) clamped((uint32_t)val,
michael@0 863 (uint32_t)1, MaxSocketCount());
michael@0 864
michael@0 865 if (mConnMgr)
michael@0 866 mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_CONNECTIONS,
michael@0 867 mMaxConnections);
michael@0 868 }
michael@0 869 }
michael@0 870
michael@0 871 if (PREF_CHANGED(HTTP_PREF("max-persistent-connections-per-server"))) {
michael@0 872 rv = prefs->GetIntPref(HTTP_PREF("max-persistent-connections-per-server"), &val);
michael@0 873 if (NS_SUCCEEDED(rv)) {
michael@0 874 mMaxPersistentConnectionsPerServer = (uint8_t) clamped(val, 1, 0xff);
michael@0 875 if (mConnMgr)
michael@0 876 mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_PERSISTENT_CONNECTIONS_PER_HOST,
michael@0 877 mMaxPersistentConnectionsPerServer);
michael@0 878 }
michael@0 879 }
michael@0 880
michael@0 881 if (PREF_CHANGED(HTTP_PREF("max-persistent-connections-per-proxy"))) {
michael@0 882 rv = prefs->GetIntPref(HTTP_PREF("max-persistent-connections-per-proxy"), &val);
michael@0 883 if (NS_SUCCEEDED(rv)) {
michael@0 884 mMaxPersistentConnectionsPerProxy = (uint8_t) clamped(val, 1, 0xff);
michael@0 885 if (mConnMgr)
michael@0 886 mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_PERSISTENT_CONNECTIONS_PER_PROXY,
michael@0 887 mMaxPersistentConnectionsPerProxy);
michael@0 888 }
michael@0 889 }
michael@0 890
michael@0 891 if (PREF_CHANGED(HTTP_PREF("sendRefererHeader"))) {
michael@0 892 rv = prefs->GetIntPref(HTTP_PREF("sendRefererHeader"), &val);
michael@0 893 if (NS_SUCCEEDED(rv))
michael@0 894 mReferrerLevel = (uint8_t) clamped(val, 0, 0xff);
michael@0 895 }
michael@0 896
michael@0 897 if (PREF_CHANGED(HTTP_PREF("referer.spoofSource"))) {
michael@0 898 rv = prefs->GetBoolPref(HTTP_PREF("referer.spoofSource"), &cVar);
michael@0 899 if (NS_SUCCEEDED(rv))
michael@0 900 mSpoofReferrerSource = cVar;
michael@0 901 }
michael@0 902
michael@0 903 if (PREF_CHANGED(HTTP_PREF("referer.trimmingPolicy"))) {
michael@0 904 rv = prefs->GetIntPref(HTTP_PREF("referer.trimmingPolicy"), &val);
michael@0 905 if (NS_SUCCEEDED(rv))
michael@0 906 mReferrerTrimmingPolicy = (uint8_t) clamped(val, 0, 0xff);
michael@0 907 }
michael@0 908
michael@0 909 if (PREF_CHANGED(HTTP_PREF("referer.XOriginPolicy"))) {
michael@0 910 rv = prefs->GetIntPref(HTTP_PREF("referer.XOriginPolicy"), &val);
michael@0 911 if (NS_SUCCEEDED(rv))
michael@0 912 mReferrerXOriginPolicy = (uint8_t) clamped(val, 0, 0xff);
michael@0 913 }
michael@0 914
michael@0 915 if (PREF_CHANGED(HTTP_PREF("redirection-limit"))) {
michael@0 916 rv = prefs->GetIntPref(HTTP_PREF("redirection-limit"), &val);
michael@0 917 if (NS_SUCCEEDED(rv))
michael@0 918 mRedirectionLimit = (uint8_t) clamped(val, 0, 0xff);
michael@0 919 }
michael@0 920
michael@0 921 if (PREF_CHANGED(HTTP_PREF("connection-retry-timeout"))) {
michael@0 922 rv = prefs->GetIntPref(HTTP_PREF("connection-retry-timeout"), &val);
michael@0 923 if (NS_SUCCEEDED(rv))
michael@0 924 mIdleSynTimeout = (uint16_t) clamped(val, 0, 3000);
michael@0 925 }
michael@0 926
michael@0 927 if (PREF_CHANGED(HTTP_PREF("fast-fallback-to-IPv4"))) {
michael@0 928 rv = prefs->GetBoolPref(HTTP_PREF("fast-fallback-to-IPv4"), &cVar);
michael@0 929 if (NS_SUCCEEDED(rv))
michael@0 930 mFastFallbackToIPv4 = cVar;
michael@0 931 }
michael@0 932
michael@0 933 if (PREF_CHANGED(HTTP_PREF("version"))) {
michael@0 934 nsXPIDLCString httpVersion;
michael@0 935 prefs->GetCharPref(HTTP_PREF("version"), getter_Copies(httpVersion));
michael@0 936 if (httpVersion) {
michael@0 937 if (!PL_strcmp(httpVersion, "1.1"))
michael@0 938 mHttpVersion = NS_HTTP_VERSION_1_1;
michael@0 939 else if (!PL_strcmp(httpVersion, "0.9"))
michael@0 940 mHttpVersion = NS_HTTP_VERSION_0_9;
michael@0 941 else
michael@0 942 mHttpVersion = NS_HTTP_VERSION_1_0;
michael@0 943 }
michael@0 944 }
michael@0 945
michael@0 946 if (PREF_CHANGED(HTTP_PREF("proxy.version"))) {
michael@0 947 nsXPIDLCString httpVersion;
michael@0 948 prefs->GetCharPref(HTTP_PREF("proxy.version"), getter_Copies(httpVersion));
michael@0 949 if (httpVersion) {
michael@0 950 if (!PL_strcmp(httpVersion, "1.1"))
michael@0 951 mProxyHttpVersion = NS_HTTP_VERSION_1_1;
michael@0 952 else
michael@0 953 mProxyHttpVersion = NS_HTTP_VERSION_1_0;
michael@0 954 // it does not make sense to issue a HTTP/0.9 request to a proxy server
michael@0 955 }
michael@0 956 }
michael@0 957
michael@0 958 if (PREF_CHANGED(HTTP_PREF("pipelining"))) {
michael@0 959 rv = prefs->GetBoolPref(HTTP_PREF("pipelining"), &cVar);
michael@0 960 if (NS_SUCCEEDED(rv)) {
michael@0 961 if (cVar)
michael@0 962 mCapabilities |= NS_HTTP_ALLOW_PIPELINING;
michael@0 963 else
michael@0 964 mCapabilities &= ~NS_HTTP_ALLOW_PIPELINING;
michael@0 965 mPipeliningEnabled = cVar;
michael@0 966 }
michael@0 967 }
michael@0 968
michael@0 969 if (PREF_CHANGED(HTTP_PREF("pipelining.maxrequests"))) {
michael@0 970 rv = prefs->GetIntPref(HTTP_PREF("pipelining.maxrequests"), &val);
michael@0 971 if (NS_SUCCEEDED(rv)) {
michael@0 972 mMaxPipelinedRequests = clamped(val, 1, 0xffff);
michael@0 973 if (mConnMgr)
michael@0 974 mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_PIPELINED_REQUESTS,
michael@0 975 mMaxPipelinedRequests);
michael@0 976 }
michael@0 977 }
michael@0 978
michael@0 979 if (PREF_CHANGED(HTTP_PREF("pipelining.max-optimistic-requests"))) {
michael@0 980 rv = prefs->
michael@0 981 GetIntPref(HTTP_PREF("pipelining.max-optimistic-requests"), &val);
michael@0 982 if (NS_SUCCEEDED(rv)) {
michael@0 983 mMaxOptimisticPipelinedRequests = clamped(val, 1, 0xffff);
michael@0 984 if (mConnMgr)
michael@0 985 mConnMgr->UpdateParam
michael@0 986 (nsHttpConnectionMgr::MAX_OPTIMISTIC_PIPELINED_REQUESTS,
michael@0 987 mMaxOptimisticPipelinedRequests);
michael@0 988 }
michael@0 989 }
michael@0 990
michael@0 991 if (PREF_CHANGED(HTTP_PREF("pipelining.aggressive"))) {
michael@0 992 rv = prefs->GetBoolPref(HTTP_PREF("pipelining.aggressive"), &cVar);
michael@0 993 if (NS_SUCCEEDED(rv))
michael@0 994 mPipelineAggressive = cVar;
michael@0 995 }
michael@0 996
michael@0 997 if (PREF_CHANGED(HTTP_PREF("pipelining.maxsize"))) {
michael@0 998 rv = prefs->GetIntPref(HTTP_PREF("pipelining.maxsize"), &val);
michael@0 999 if (NS_SUCCEEDED(rv)) {
michael@0 1000 mMaxPipelineObjectSize =
michael@0 1001 static_cast<int64_t>(clamped(val, 1000, 100000000));
michael@0 1002 }
michael@0 1003 }
michael@0 1004
michael@0 1005 // Determines whether or not to actually reschedule after the
michael@0 1006 // reschedule-timeout has expired
michael@0 1007 if (PREF_CHANGED(HTTP_PREF("pipelining.reschedule-on-timeout"))) {
michael@0 1008 rv = prefs->GetBoolPref(HTTP_PREF("pipelining.reschedule-on-timeout"),
michael@0 1009 &cVar);
michael@0 1010 if (NS_SUCCEEDED(rv))
michael@0 1011 mPipelineRescheduleOnTimeout = cVar;
michael@0 1012 }
michael@0 1013
michael@0 1014 // The amount of time head of line blocking is allowed (in ms)
michael@0 1015 // before the blocked transactions are moved to another pipeline
michael@0 1016 if (PREF_CHANGED(HTTP_PREF("pipelining.reschedule-timeout"))) {
michael@0 1017 rv = prefs->GetIntPref(HTTP_PREF("pipelining.reschedule-timeout"),
michael@0 1018 &val);
michael@0 1019 if (NS_SUCCEEDED(rv)) {
michael@0 1020 mPipelineRescheduleTimeout =
michael@0 1021 PR_MillisecondsToInterval((uint16_t) clamped(val, 500, 0xffff));
michael@0 1022 }
michael@0 1023 }
michael@0 1024
michael@0 1025 // The amount of time a pipelined transaction is allowed to wait before
michael@0 1026 // being canceled and retried in a non-pipeline connection
michael@0 1027 if (PREF_CHANGED(HTTP_PREF("pipelining.read-timeout"))) {
michael@0 1028 rv = prefs->GetIntPref(HTTP_PREF("pipelining.read-timeout"), &val);
michael@0 1029 if (NS_SUCCEEDED(rv)) {
michael@0 1030 mPipelineReadTimeout =
michael@0 1031 PR_MillisecondsToInterval((uint16_t) clamped(val, 5000,
michael@0 1032 0xffff));
michael@0 1033 }
michael@0 1034 }
michael@0 1035
michael@0 1036 if (PREF_CHANGED(HTTP_PREF("pipelining.ssl"))) {
michael@0 1037 rv = prefs->GetBoolPref(HTTP_PREF("pipelining.ssl"), &cVar);
michael@0 1038 if (NS_SUCCEEDED(rv))
michael@0 1039 mPipeliningOverSSL = cVar;
michael@0 1040 }
michael@0 1041
michael@0 1042 if (PREF_CHANGED(HTTP_PREF("proxy.pipelining"))) {
michael@0 1043 rv = prefs->GetBoolPref(HTTP_PREF("proxy.pipelining"), &cVar);
michael@0 1044 if (NS_SUCCEEDED(rv))
michael@0 1045 mProxyPipelining = cVar;
michael@0 1046 }
michael@0 1047
michael@0 1048 if (PREF_CHANGED(HTTP_PREF("qos"))) {
michael@0 1049 rv = prefs->GetIntPref(HTTP_PREF("qos"), &val);
michael@0 1050 if (NS_SUCCEEDED(rv))
michael@0 1051 mQoSBits = (uint8_t) clamped(val, 0, 0xff);
michael@0 1052 }
michael@0 1053
michael@0 1054 if (PREF_CHANGED(HTTP_PREF("sendSecureXSiteReferrer"))) {
michael@0 1055 rv = prefs->GetBoolPref(HTTP_PREF("sendSecureXSiteReferrer"), &cVar);
michael@0 1056 if (NS_SUCCEEDED(rv))
michael@0 1057 mSendSecureXSiteReferrer = cVar;
michael@0 1058 }
michael@0 1059
michael@0 1060 if (PREF_CHANGED(HTTP_PREF("accept.default"))) {
michael@0 1061 nsXPIDLCString accept;
michael@0 1062 rv = prefs->GetCharPref(HTTP_PREF("accept.default"),
michael@0 1063 getter_Copies(accept));
michael@0 1064 if (NS_SUCCEEDED(rv))
michael@0 1065 SetAccept(accept);
michael@0 1066 }
michael@0 1067
michael@0 1068 if (PREF_CHANGED(HTTP_PREF("accept-encoding"))) {
michael@0 1069 nsXPIDLCString acceptEncodings;
michael@0 1070 rv = prefs->GetCharPref(HTTP_PREF("accept-encoding"),
michael@0 1071 getter_Copies(acceptEncodings));
michael@0 1072 if (NS_SUCCEEDED(rv))
michael@0 1073 SetAcceptEncodings(acceptEncodings);
michael@0 1074 }
michael@0 1075
michael@0 1076 if (PREF_CHANGED(HTTP_PREF("use-cache"))) {
michael@0 1077 rv = prefs->GetBoolPref(HTTP_PREF("use-cache"), &cVar);
michael@0 1078 if (NS_SUCCEEDED(rv)) {
michael@0 1079 mUseCache = cVar;
michael@0 1080 }
michael@0 1081 }
michael@0 1082
michael@0 1083 if (PREF_CHANGED(HTTP_PREF("default-socket-type"))) {
michael@0 1084 nsXPIDLCString sval;
michael@0 1085 rv = prefs->GetCharPref(HTTP_PREF("default-socket-type"),
michael@0 1086 getter_Copies(sval));
michael@0 1087 if (NS_SUCCEEDED(rv)) {
michael@0 1088 if (sval.IsEmpty())
michael@0 1089 mDefaultSocketType.Adopt(0);
michael@0 1090 else {
michael@0 1091 // verify that this socket type is actually valid
michael@0 1092 nsCOMPtr<nsISocketProviderService> sps(
michael@0 1093 do_GetService(NS_SOCKETPROVIDERSERVICE_CONTRACTID));
michael@0 1094 if (sps) {
michael@0 1095 nsCOMPtr<nsISocketProvider> sp;
michael@0 1096 rv = sps->GetSocketProvider(sval, getter_AddRefs(sp));
michael@0 1097 if (NS_SUCCEEDED(rv)) {
michael@0 1098 // OK, this looks like a valid socket provider.
michael@0 1099 mDefaultSocketType.Assign(sval);
michael@0 1100 }
michael@0 1101 }
michael@0 1102 }
michael@0 1103 }
michael@0 1104 }
michael@0 1105
michael@0 1106 if (PREF_CHANGED(HTTP_PREF("prompt-temp-redirect"))) {
michael@0 1107 rv = prefs->GetBoolPref(HTTP_PREF("prompt-temp-redirect"), &cVar);
michael@0 1108 if (NS_SUCCEEDED(rv)) {
michael@0 1109 mPromptTempRedirect = cVar;
michael@0 1110 }
michael@0 1111 }
michael@0 1112
michael@0 1113 if (PREF_CHANGED(HTTP_PREF("assoc-req.enforce"))) {
michael@0 1114 cVar = false;
michael@0 1115 rv = prefs->GetBoolPref(HTTP_PREF("assoc-req.enforce"), &cVar);
michael@0 1116 if (NS_SUCCEEDED(rv))
michael@0 1117 mEnforceAssocReq = cVar;
michael@0 1118 }
michael@0 1119
michael@0 1120 // enable Persistent caching for HTTPS - bug#205921
michael@0 1121 if (PREF_CHANGED(BROWSER_PREF("disk_cache_ssl"))) {
michael@0 1122 cVar = false;
michael@0 1123 rv = prefs->GetBoolPref(BROWSER_PREF("disk_cache_ssl"), &cVar);
michael@0 1124 if (NS_SUCCEEDED(rv))
michael@0 1125 mEnablePersistentHttpsCaching = cVar;
michael@0 1126 }
michael@0 1127
michael@0 1128 if (PREF_CHANGED(HTTP_PREF("phishy-userpass-length"))) {
michael@0 1129 rv = prefs->GetIntPref(HTTP_PREF("phishy-userpass-length"), &val);
michael@0 1130 if (NS_SUCCEEDED(rv))
michael@0 1131 mPhishyUserPassLength = (uint8_t) clamped(val, 0, 0xff);
michael@0 1132 }
michael@0 1133
michael@0 1134 if (PREF_CHANGED(HTTP_PREF("spdy.enabled"))) {
michael@0 1135 rv = prefs->GetBoolPref(HTTP_PREF("spdy.enabled"), &cVar);
michael@0 1136 if (NS_SUCCEEDED(rv))
michael@0 1137 mEnableSpdy = cVar;
michael@0 1138 }
michael@0 1139
michael@0 1140 if (PREF_CHANGED(HTTP_PREF("spdy.enabled.v3"))) {
michael@0 1141 rv = prefs->GetBoolPref(HTTP_PREF("spdy.enabled.v3"), &cVar);
michael@0 1142 if (NS_SUCCEEDED(rv))
michael@0 1143 mSpdyV3 = cVar;
michael@0 1144 }
michael@0 1145
michael@0 1146 if (PREF_CHANGED(HTTP_PREF("spdy.enabled.v3-1"))) {
michael@0 1147 rv = prefs->GetBoolPref(HTTP_PREF("spdy.enabled.v3-1"), &cVar);
michael@0 1148 if (NS_SUCCEEDED(rv))
michael@0 1149 mSpdyV31 = cVar;
michael@0 1150 }
michael@0 1151
michael@0 1152 if (PREF_CHANGED(HTTP_PREF("spdy.enabled.http2draft"))) {
michael@0 1153 rv = prefs->GetBoolPref(HTTP_PREF("spdy.enabled.http2draft"), &cVar);
michael@0 1154 if (NS_SUCCEEDED(rv))
michael@0 1155 mHttp2DraftEnabled = cVar;
michael@0 1156 }
michael@0 1157
michael@0 1158 if (PREF_CHANGED(HTTP_PREF("spdy.enforce-tls-profile"))) {
michael@0 1159 rv = prefs->GetBoolPref(HTTP_PREF("spdy.enforce-tls-profile"), &cVar);
michael@0 1160 if (NS_SUCCEEDED(rv))
michael@0 1161 mEnforceHttp2TlsProfile = cVar;
michael@0 1162 }
michael@0 1163
michael@0 1164 if (PREF_CHANGED(HTTP_PREF("spdy.coalesce-hostnames"))) {
michael@0 1165 rv = prefs->GetBoolPref(HTTP_PREF("spdy.coalesce-hostnames"), &cVar);
michael@0 1166 if (NS_SUCCEEDED(rv))
michael@0 1167 mCoalesceSpdy = cVar;
michael@0 1168 }
michael@0 1169
michael@0 1170 if (PREF_CHANGED(HTTP_PREF("spdy.persistent-settings"))) {
michael@0 1171 rv = prefs->GetBoolPref(HTTP_PREF("spdy.persistent-settings"),
michael@0 1172 &cVar);
michael@0 1173 if (NS_SUCCEEDED(rv))
michael@0 1174 mSpdyPersistentSettings = cVar;
michael@0 1175 }
michael@0 1176
michael@0 1177 if (PREF_CHANGED(HTTP_PREF("spdy.timeout"))) {
michael@0 1178 rv = prefs->GetIntPref(HTTP_PREF("spdy.timeout"), &val);
michael@0 1179 if (NS_SUCCEEDED(rv))
michael@0 1180 mSpdyTimeout = PR_SecondsToInterval(clamped(val, 1, 0xffff));
michael@0 1181 }
michael@0 1182
michael@0 1183 if (PREF_CHANGED(HTTP_PREF("spdy.chunk-size"))) {
michael@0 1184 // keep this within http/2 ranges of 1 to 2^14-1
michael@0 1185 rv = prefs->GetIntPref(HTTP_PREF("spdy.chunk-size"), &val);
michael@0 1186 if (NS_SUCCEEDED(rv))
michael@0 1187 mSpdySendingChunkSize = (uint32_t) clamped(val, 1, 0x3fff);
michael@0 1188 }
michael@0 1189
michael@0 1190 // The amount of idle seconds on a spdy connection before initiating a
michael@0 1191 // server ping. 0 will disable.
michael@0 1192 if (PREF_CHANGED(HTTP_PREF("spdy.ping-threshold"))) {
michael@0 1193 rv = prefs->GetIntPref(HTTP_PREF("spdy.ping-threshold"), &val);
michael@0 1194 if (NS_SUCCEEDED(rv))
michael@0 1195 mSpdyPingThreshold =
michael@0 1196 PR_SecondsToInterval((uint16_t) clamped(val, 0, 0x7fffffff));
michael@0 1197 }
michael@0 1198
michael@0 1199 // The amount of seconds to wait for a spdy ping response before
michael@0 1200 // closing the session.
michael@0 1201 if (PREF_CHANGED(HTTP_PREF("spdy.ping-timeout"))) {
michael@0 1202 rv = prefs->GetIntPref(HTTP_PREF("spdy.ping-timeout"), &val);
michael@0 1203 if (NS_SUCCEEDED(rv))
michael@0 1204 mSpdyPingTimeout =
michael@0 1205 PR_SecondsToInterval((uint16_t) clamped(val, 0, 0x7fffffff));
michael@0 1206 }
michael@0 1207
michael@0 1208 if (PREF_CHANGED(HTTP_PREF("spdy.allow-push"))) {
michael@0 1209 rv = prefs->GetBoolPref(HTTP_PREF("spdy.allow-push"),
michael@0 1210 &cVar);
michael@0 1211 if (NS_SUCCEEDED(rv))
michael@0 1212 mAllowPush = cVar;
michael@0 1213 }
michael@0 1214
michael@0 1215 if (PREF_CHANGED(HTTP_PREF("spdy.push-allowance"))) {
michael@0 1216 rv = prefs->GetIntPref(HTTP_PREF("spdy.push-allowance"), &val);
michael@0 1217 if (NS_SUCCEEDED(rv)) {
michael@0 1218 mSpdyPushAllowance =
michael@0 1219 static_cast<uint32_t>
michael@0 1220 (clamped(val, 1024, static_cast<int32_t>(ASpdySession::kInitialRwin)));
michael@0 1221 }
michael@0 1222 }
michael@0 1223
michael@0 1224 // The amount of seconds to wait for a spdy ping response before
michael@0 1225 // closing the session.
michael@0 1226 if (PREF_CHANGED(HTTP_PREF("spdy.send-buffer-size"))) {
michael@0 1227 rv = prefs->GetIntPref(HTTP_PREF("spdy.send-buffer-size"), &val);
michael@0 1228 if (NS_SUCCEEDED(rv))
michael@0 1229 mSpdySendBufferSize = (uint32_t) clamped(val, 1500, 0x7fffffff);
michael@0 1230 }
michael@0 1231
michael@0 1232 // The maximum amount of time to wait for socket transport to be
michael@0 1233 // established
michael@0 1234 if (PREF_CHANGED(HTTP_PREF("connection-timeout"))) {
michael@0 1235 rv = prefs->GetIntPref(HTTP_PREF("connection-timeout"), &val);
michael@0 1236 if (NS_SUCCEEDED(rv))
michael@0 1237 // the pref is in seconds, but the variable is in milliseconds
michael@0 1238 mConnectTimeout = clamped(val, 1, 0xffff) * PR_MSEC_PER_SEC;
michael@0 1239 }
michael@0 1240
michael@0 1241 // The maximum amount of time the cache session lock can be held
michael@0 1242 // before a new transaction bypasses the cache. In milliseconds.
michael@0 1243 if (PREF_CHANGED(HTTP_PREF("bypass-cachelock-threshold"))) {
michael@0 1244 rv = prefs->GetIntPref(HTTP_PREF("bypass-cachelock-threshold"), &val);
michael@0 1245 if (NS_SUCCEEDED(rv))
michael@0 1246 // the pref and variable are both in milliseconds
michael@0 1247 mBypassCacheLockThreshold =
michael@0 1248 static_cast<double>(clamped(val, 0, 0x7ffffff));
michael@0 1249 }
michael@0 1250
michael@0 1251 // The maximum number of current global half open sockets allowable
michael@0 1252 // for starting a new speculative connection.
michael@0 1253 if (PREF_CHANGED(HTTP_PREF("speculative-parallel-limit"))) {
michael@0 1254 rv = prefs->GetIntPref(HTTP_PREF("speculative-parallel-limit"), &val);
michael@0 1255 if (NS_SUCCEEDED(rv))
michael@0 1256 mParallelSpeculativeConnectLimit = (uint32_t) clamped(val, 0, 1024);
michael@0 1257 }
michael@0 1258
michael@0 1259 // Whether or not to block requests for non head js/css items (e.g. media)
michael@0 1260 // while those elements load.
michael@0 1261 if (PREF_CHANGED(HTTP_PREF("rendering-critical-requests-prioritization"))) {
michael@0 1262 rv = prefs->GetBoolPref(HTTP_PREF("rendering-critical-requests-prioritization"), &cVar);
michael@0 1263 if (NS_SUCCEEDED(rv))
michael@0 1264 mCriticalRequestPrioritization = cVar;
michael@0 1265 }
michael@0 1266
michael@0 1267 // on transition of network.http.diagnostics to true print
michael@0 1268 // a bunch of information to the console
michael@0 1269 if (pref && PREF_CHANGED(HTTP_PREF("diagnostics"))) {
michael@0 1270 rv = prefs->GetBoolPref(HTTP_PREF("diagnostics"), &cVar);
michael@0 1271 if (NS_SUCCEEDED(rv) && cVar) {
michael@0 1272 if (mConnMgr)
michael@0 1273 mConnMgr->PrintDiagnostics();
michael@0 1274 }
michael@0 1275 }
michael@0 1276 //
michael@0 1277 // INTL options
michael@0 1278 //
michael@0 1279
michael@0 1280 if (PREF_CHANGED(INTL_ACCEPT_LANGUAGES)) {
michael@0 1281 nsCOMPtr<nsIPrefLocalizedString> pls;
michael@0 1282 prefs->GetComplexValue(INTL_ACCEPT_LANGUAGES,
michael@0 1283 NS_GET_IID(nsIPrefLocalizedString),
michael@0 1284 getter_AddRefs(pls));
michael@0 1285 if (pls) {
michael@0 1286 nsXPIDLString uval;
michael@0 1287 pls->ToString(getter_Copies(uval));
michael@0 1288 if (uval)
michael@0 1289 SetAcceptLanguages(NS_ConvertUTF16toUTF8(uval).get());
michael@0 1290 }
michael@0 1291 }
michael@0 1292
michael@0 1293 //
michael@0 1294 // Tracking options
michael@0 1295 //
michael@0 1296
michael@0 1297 if (PREF_CHANGED(DONOTTRACK_HEADER_ENABLED)) {
michael@0 1298 cVar = false;
michael@0 1299 rv = prefs->GetBoolPref(DONOTTRACK_HEADER_ENABLED, &cVar);
michael@0 1300 if (NS_SUCCEEDED(rv)) {
michael@0 1301 mDoNotTrackEnabled = cVar;
michael@0 1302 }
michael@0 1303 }
michael@0 1304 if (PREF_CHANGED(DONOTTRACK_HEADER_VALUE)) {
michael@0 1305 val = 1;
michael@0 1306 rv = prefs->GetIntPref(DONOTTRACK_HEADER_VALUE, &val);
michael@0 1307 if (NS_SUCCEEDED(rv)) {
michael@0 1308 mDoNotTrackValue = val;
michael@0 1309 }
michael@0 1310 }
michael@0 1311
michael@0 1312 // Hint option
michael@0 1313 if (PREF_CHANGED(SAFE_HINT_HEADER_VALUE)) {
michael@0 1314 cVar = false;
michael@0 1315 rv = prefs->GetBoolPref(SAFE_HINT_HEADER_VALUE, &cVar);
michael@0 1316 if (NS_SUCCEEDED(rv)) {
michael@0 1317 mSafeHintEnabled = cVar;
michael@0 1318 }
michael@0 1319 }
michael@0 1320
michael@0 1321 // toggle to true anytime a token bucket related pref is changed.. that
michael@0 1322 // includes telemetry and allow-experiments because of the abtest profile
michael@0 1323 bool requestTokenBucketUpdated = false;
michael@0 1324
michael@0 1325 //
michael@0 1326 // Telemetry
michael@0 1327 //
michael@0 1328
michael@0 1329 if (PREF_CHANGED(TELEMETRY_ENABLED)) {
michael@0 1330 cVar = false;
michael@0 1331 requestTokenBucketUpdated = true;
michael@0 1332 rv = prefs->GetBoolPref(TELEMETRY_ENABLED, &cVar);
michael@0 1333 if (NS_SUCCEEDED(rv)) {
michael@0 1334 mTelemetryEnabled = cVar;
michael@0 1335 }
michael@0 1336 }
michael@0 1337
michael@0 1338 //
michael@0 1339 // network.allow-experiments
michael@0 1340 //
michael@0 1341 if (PREF_CHANGED(ALLOW_EXPERIMENTS)) {
michael@0 1342 cVar = true;
michael@0 1343 requestTokenBucketUpdated = true;
michael@0 1344 rv = prefs->GetBoolPref(ALLOW_EXPERIMENTS, &cVar);
michael@0 1345 if (NS_SUCCEEDED(rv)) {
michael@0 1346 mAllowExperiments = cVar;
michael@0 1347 }
michael@0 1348 }
michael@0 1349
michael@0 1350 //
michael@0 1351 // Test HTTP Pipelining (bug796192)
michael@0 1352 // If experiments are allowed and pipelining is Off,
michael@0 1353 // turn it On for just 10 minutes
michael@0 1354 //
michael@0 1355 if (mAllowExperiments && !mPipeliningEnabled &&
michael@0 1356 PREF_CHANGED(HTTP_PREF("pipelining.abtest"))) {
michael@0 1357 rv = prefs->GetBoolPref(HTTP_PREF("pipelining.abtest"), &cVar);
michael@0 1358 if (NS_SUCCEEDED(rv)) {
michael@0 1359 // If option is enabled, only test for ~1% of sessions
michael@0 1360 if (cVar && !(rand() % 128)) {
michael@0 1361 mCapabilities |= NS_HTTP_ALLOW_PIPELINING;
michael@0 1362 if (mPipelineTestTimer)
michael@0 1363 mPipelineTestTimer->Cancel();
michael@0 1364 mPipelineTestTimer =
michael@0 1365 do_CreateInstance("@mozilla.org/timer;1", &rv);
michael@0 1366 if (NS_SUCCEEDED(rv)) {
michael@0 1367 rv = mPipelineTestTimer->InitWithFuncCallback(
michael@0 1368 TimerCallback, this, 10*60*1000, // 10 minutes
michael@0 1369 nsITimer::TYPE_ONE_SHOT);
michael@0 1370 }
michael@0 1371 } else {
michael@0 1372 mCapabilities &= ~NS_HTTP_ALLOW_PIPELINING;
michael@0 1373 if (mPipelineTestTimer) {
michael@0 1374 mPipelineTestTimer->Cancel();
michael@0 1375 mPipelineTestTimer = nullptr;
michael@0 1376 }
michael@0 1377 }
michael@0 1378 }
michael@0 1379 }
michael@0 1380 if (requestTokenBucketUpdated) {
michael@0 1381 MakeNewRequestTokenBucket();
michael@0 1382 }
michael@0 1383
michael@0 1384 if (PREF_CHANGED(HTTP_PREF("pacing.requests.enabled"))) {
michael@0 1385 rv = prefs->GetBoolPref(HTTP_PREF("pacing.requests.enabled"),
michael@0 1386 &cVar);
michael@0 1387 if (NS_SUCCEEDED(rv)){
michael@0 1388 requestTokenBucketUpdated = true;
michael@0 1389 mRequestTokenBucketEnabled = cVar;
michael@0 1390 }
michael@0 1391 }
michael@0 1392
michael@0 1393 if (PREF_CHANGED(HTTP_PREF("pacing.requests.min-parallelism"))) {
michael@0 1394 rv = prefs->GetIntPref(HTTP_PREF("pacing.requests.min-parallelism"), &val);
michael@0 1395 if (NS_SUCCEEDED(rv))
michael@0 1396 mRequestTokenBucketMinParallelism = static_cast<uint16_t>(clamped(val, 1, 1024));
michael@0 1397 }
michael@0 1398 if (PREF_CHANGED(HTTP_PREF("pacing.requests.hz"))) {
michael@0 1399 rv = prefs->GetIntPref(HTTP_PREF("pacing.requests.hz"), &val);
michael@0 1400 if (NS_SUCCEEDED(rv)) {
michael@0 1401 mRequestTokenBucketHz = static_cast<uint32_t>(clamped(val, 1, 10000));
michael@0 1402 requestTokenBucketUpdated = true;
michael@0 1403 }
michael@0 1404 }
michael@0 1405 if (PREF_CHANGED(HTTP_PREF("pacing.requests.burst"))) {
michael@0 1406 rv = prefs->GetIntPref(HTTP_PREF("pacing.requests.burst"), &val);
michael@0 1407 if (NS_SUCCEEDED(rv)) {
michael@0 1408 mRequestTokenBucketBurst = val ? val : 1;
michael@0 1409 requestTokenBucketUpdated = true;
michael@0 1410 }
michael@0 1411 }
michael@0 1412 if (requestTokenBucketUpdated) {
michael@0 1413 mRequestTokenBucket =
michael@0 1414 new EventTokenBucket(RequestTokenBucketHz(),
michael@0 1415 RequestTokenBucketBurst());
michael@0 1416 }
michael@0 1417
michael@0 1418 // Keepalive values for initial and idle connections.
michael@0 1419 if (PREF_CHANGED(HTTP_PREF("tcp_keepalive.short_lived_connections"))) {
michael@0 1420 rv = prefs->GetBoolPref(
michael@0 1421 HTTP_PREF("tcp_keepalive.short_lived_connections"), &cVar);
michael@0 1422 if (NS_SUCCEEDED(rv) && cVar != mTCPKeepaliveShortLivedEnabled) {
michael@0 1423 mTCPKeepaliveShortLivedEnabled = cVar;
michael@0 1424 }
michael@0 1425 }
michael@0 1426
michael@0 1427 if (PREF_CHANGED(HTTP_PREF("tcp_keepalive.short_lived_time"))) {
michael@0 1428 rv = prefs->GetIntPref(
michael@0 1429 HTTP_PREF("tcp_keepalive.short_lived_time"), &val);
michael@0 1430 if (NS_SUCCEEDED(rv) && val > 0)
michael@0 1431 mTCPKeepaliveShortLivedTimeS = clamped(val, 1, 300); // Max 5 mins.
michael@0 1432 }
michael@0 1433
michael@0 1434 if (PREF_CHANGED(HTTP_PREF("tcp_keepalive.short_lived_idle_time"))) {
michael@0 1435 rv = prefs->GetIntPref(
michael@0 1436 HTTP_PREF("tcp_keepalive.short_lived_idle_time"), &val);
michael@0 1437 if (NS_SUCCEEDED(rv) && val > 0)
michael@0 1438 mTCPKeepaliveShortLivedIdleTimeS = clamped(val,
michael@0 1439 1, kMaxTCPKeepIdle);
michael@0 1440 }
michael@0 1441
michael@0 1442 // Keepalive values for Long-lived Connections.
michael@0 1443 if (PREF_CHANGED(HTTP_PREF("tcp_keepalive.long_lived_connections"))) {
michael@0 1444 rv = prefs->GetBoolPref(
michael@0 1445 HTTP_PREF("tcp_keepalive.long_lived_connections"), &cVar);
michael@0 1446 if (NS_SUCCEEDED(rv) && cVar != mTCPKeepaliveLongLivedEnabled) {
michael@0 1447 mTCPKeepaliveLongLivedEnabled = cVar;
michael@0 1448 }
michael@0 1449 }
michael@0 1450
michael@0 1451 if (PREF_CHANGED(HTTP_PREF("tcp_keepalive.long_lived_idle_time"))) {
michael@0 1452 rv = prefs->GetIntPref(
michael@0 1453 HTTP_PREF("tcp_keepalive.long_lived_idle_time"), &val);
michael@0 1454 if (NS_SUCCEEDED(rv) && val > 0)
michael@0 1455 mTCPKeepaliveLongLivedIdleTimeS = clamped(val,
michael@0 1456 1, kMaxTCPKeepIdle);
michael@0 1457 }
michael@0 1458
michael@0 1459 // Enable HTTP response timeout if TCP Keepalives are disabled.
michael@0 1460 mResponseTimeoutEnabled = !mTCPKeepaliveShortLivedEnabled &&
michael@0 1461 !mTCPKeepaliveLongLivedEnabled;
michael@0 1462
michael@0 1463 #undef PREF_CHANGED
michael@0 1464 #undef MULTI_PREF_CHANGED
michael@0 1465 }
michael@0 1466
michael@0 1467
michael@0 1468 /**
michael@0 1469 * Static method called by mPipelineTestTimer when it expires.
michael@0 1470 */
michael@0 1471 void
michael@0 1472 nsHttpHandler::TimerCallback(nsITimer * aTimer, void * aClosure)
michael@0 1473 {
michael@0 1474 nsRefPtr<nsHttpHandler> thisObject = static_cast<nsHttpHandler*>(aClosure);
michael@0 1475 if (!thisObject->mPipeliningEnabled)
michael@0 1476 thisObject->mCapabilities &= ~NS_HTTP_ALLOW_PIPELINING;
michael@0 1477 }
michael@0 1478
michael@0 1479 /**
michael@0 1480 * Allocates a C string into that contains a ISO 639 language list
michael@0 1481 * notated with HTTP "q" values for output with a HTTP Accept-Language
michael@0 1482 * header. Previous q values will be stripped because the order of
michael@0 1483 * the langs imply the q value. The q values are calculated by dividing
michael@0 1484 * 1.0 amongst the number of languages present.
michael@0 1485 *
michael@0 1486 * Ex: passing: "en, ja"
michael@0 1487 * returns: "en,ja;q=0.5"
michael@0 1488 *
michael@0 1489 * passing: "en, ja, fr_CA"
michael@0 1490 * returns: "en,ja;q=0.7,fr_CA;q=0.3"
michael@0 1491 */
michael@0 1492 static nsresult
michael@0 1493 PrepareAcceptLanguages(const char *i_AcceptLanguages, nsACString &o_AcceptLanguages)
michael@0 1494 {
michael@0 1495 if (!i_AcceptLanguages)
michael@0 1496 return NS_OK;
michael@0 1497
michael@0 1498 uint32_t n, count_n, size, wrote;
michael@0 1499 double q, dec;
michael@0 1500 char *p, *p2, *token, *q_Accept, *o_Accept;
michael@0 1501 const char *comma;
michael@0 1502 int32_t available;
michael@0 1503
michael@0 1504 o_Accept = strdup(i_AcceptLanguages);
michael@0 1505 if (!o_Accept)
michael@0 1506 return NS_ERROR_OUT_OF_MEMORY;
michael@0 1507 for (p = o_Accept, n = size = 0; '\0' != *p; p++) {
michael@0 1508 if (*p == ',') n++;
michael@0 1509 size++;
michael@0 1510 }
michael@0 1511
michael@0 1512 available = size + ++n * 11 + 1;
michael@0 1513 q_Accept = new char[available];
michael@0 1514 if (!q_Accept) {
michael@0 1515 free(o_Accept);
michael@0 1516 return NS_ERROR_OUT_OF_MEMORY;
michael@0 1517 }
michael@0 1518 *q_Accept = '\0';
michael@0 1519 q = 1.0;
michael@0 1520 dec = q / (double) n;
michael@0 1521 count_n = 0;
michael@0 1522 p2 = q_Accept;
michael@0 1523 for (token = nsCRT::strtok(o_Accept, ",", &p);
michael@0 1524 token != (char *) 0;
michael@0 1525 token = nsCRT::strtok(p, ",", &p))
michael@0 1526 {
michael@0 1527 token = net_FindCharNotInSet(token, HTTP_LWS);
michael@0 1528 char* trim;
michael@0 1529 trim = net_FindCharInSet(token, ";" HTTP_LWS);
michael@0 1530 if (trim != (char*)0) // remove "; q=..." if present
michael@0 1531 *trim = '\0';
michael@0 1532
michael@0 1533 if (*token != '\0') {
michael@0 1534 comma = count_n++ != 0 ? "," : ""; // delimiter if not first item
michael@0 1535 uint32_t u = QVAL_TO_UINT(q);
michael@0 1536
michael@0 1537 // Only display q-value if less than 1.00.
michael@0 1538 if (u < 100) {
michael@0 1539 const char *qval_str;
michael@0 1540
michael@0 1541 // With a small number of languages, one decimal place is enough to prevent duplicate q-values.
michael@0 1542 // Also, trailing zeroes do not add any information, so they can be removed.
michael@0 1543 if ((n < 10) || ((u % 10) == 0)) {
michael@0 1544 u = (u + 5) / 10;
michael@0 1545 qval_str = "%s%s;q=0.%u";
michael@0 1546 } else {
michael@0 1547 // Values below 10 require zero padding.
michael@0 1548 qval_str = "%s%s;q=0.%02u";
michael@0 1549 }
michael@0 1550
michael@0 1551 wrote = PR_snprintf(p2, available, qval_str, comma, token, u);
michael@0 1552 } else {
michael@0 1553 wrote = PR_snprintf(p2, available, "%s%s", comma, token);
michael@0 1554 }
michael@0 1555
michael@0 1556 q -= dec;
michael@0 1557 p2 += wrote;
michael@0 1558 available -= wrote;
michael@0 1559 MOZ_ASSERT(available > 0, "allocated string not long enough");
michael@0 1560 }
michael@0 1561 }
michael@0 1562 free(o_Accept);
michael@0 1563
michael@0 1564 o_AcceptLanguages.Assign((const char *) q_Accept);
michael@0 1565 delete [] q_Accept;
michael@0 1566
michael@0 1567 return NS_OK;
michael@0 1568 }
michael@0 1569
michael@0 1570 nsresult
michael@0 1571 nsHttpHandler::SetAcceptLanguages(const char *aAcceptLanguages)
michael@0 1572 {
michael@0 1573 nsAutoCString buf;
michael@0 1574 nsresult rv = PrepareAcceptLanguages(aAcceptLanguages, buf);
michael@0 1575 if (NS_SUCCEEDED(rv))
michael@0 1576 mAcceptLanguages.Assign(buf);
michael@0 1577 return rv;
michael@0 1578 }
michael@0 1579
michael@0 1580 nsresult
michael@0 1581 nsHttpHandler::SetAccept(const char *aAccept)
michael@0 1582 {
michael@0 1583 mAccept = aAccept;
michael@0 1584 return NS_OK;
michael@0 1585 }
michael@0 1586
michael@0 1587 nsresult
michael@0 1588 nsHttpHandler::SetAcceptEncodings(const char *aAcceptEncodings)
michael@0 1589 {
michael@0 1590 mAcceptEncodings = aAcceptEncodings;
michael@0 1591 return NS_OK;
michael@0 1592 }
michael@0 1593
michael@0 1594 //-----------------------------------------------------------------------------
michael@0 1595 // nsHttpHandler::nsISupports
michael@0 1596 //-----------------------------------------------------------------------------
michael@0 1597
michael@0 1598 NS_IMPL_ISUPPORTS(nsHttpHandler,
michael@0 1599 nsIHttpProtocolHandler,
michael@0 1600 nsIProxiedProtocolHandler,
michael@0 1601 nsIProtocolHandler,
michael@0 1602 nsIObserver,
michael@0 1603 nsISupportsWeakReference,
michael@0 1604 nsISpeculativeConnect)
michael@0 1605
michael@0 1606 //-----------------------------------------------------------------------------
michael@0 1607 // nsHttpHandler::nsIProtocolHandler
michael@0 1608 //-----------------------------------------------------------------------------
michael@0 1609
michael@0 1610 NS_IMETHODIMP
michael@0 1611 nsHttpHandler::GetScheme(nsACString &aScheme)
michael@0 1612 {
michael@0 1613 aScheme.AssignLiteral("http");
michael@0 1614 return NS_OK;
michael@0 1615 }
michael@0 1616
michael@0 1617 NS_IMETHODIMP
michael@0 1618 nsHttpHandler::GetDefaultPort(int32_t *result)
michael@0 1619 {
michael@0 1620 *result = NS_HTTP_DEFAULT_PORT;
michael@0 1621 return NS_OK;
michael@0 1622 }
michael@0 1623
michael@0 1624 NS_IMETHODIMP
michael@0 1625 nsHttpHandler::GetProtocolFlags(uint32_t *result)
michael@0 1626 {
michael@0 1627 *result = NS_HTTP_PROTOCOL_FLAGS;
michael@0 1628 return NS_OK;
michael@0 1629 }
michael@0 1630
michael@0 1631 NS_IMETHODIMP
michael@0 1632 nsHttpHandler::NewURI(const nsACString &aSpec,
michael@0 1633 const char *aCharset,
michael@0 1634 nsIURI *aBaseURI,
michael@0 1635 nsIURI **aURI)
michael@0 1636 {
michael@0 1637 return mozilla::net::NewURI(aSpec, aCharset, aBaseURI, NS_HTTP_DEFAULT_PORT, aURI);
michael@0 1638 }
michael@0 1639
michael@0 1640 NS_IMETHODIMP
michael@0 1641 nsHttpHandler::NewChannel(nsIURI *uri, nsIChannel **result)
michael@0 1642 {
michael@0 1643 LOG(("nsHttpHandler::NewChannel\n"));
michael@0 1644
michael@0 1645 NS_ENSURE_ARG_POINTER(uri);
michael@0 1646 NS_ENSURE_ARG_POINTER(result);
michael@0 1647
michael@0 1648 bool isHttp = false, isHttps = false;
michael@0 1649
michael@0 1650 // Verify that we have been given a valid scheme
michael@0 1651 nsresult rv = uri->SchemeIs("http", &isHttp);
michael@0 1652 if (NS_FAILED(rv)) return rv;
michael@0 1653 if (!isHttp) {
michael@0 1654 rv = uri->SchemeIs("https", &isHttps);
michael@0 1655 if (NS_FAILED(rv)) return rv;
michael@0 1656 if (!isHttps) {
michael@0 1657 NS_WARNING("Invalid URI scheme");
michael@0 1658 return NS_ERROR_UNEXPECTED;
michael@0 1659 }
michael@0 1660 }
michael@0 1661
michael@0 1662 return NewProxiedChannel(uri, nullptr, 0, nullptr, result);
michael@0 1663 }
michael@0 1664
michael@0 1665 NS_IMETHODIMP
michael@0 1666 nsHttpHandler::AllowPort(int32_t port, const char *scheme, bool *_retval)
michael@0 1667 {
michael@0 1668 // don't override anything.
michael@0 1669 *_retval = false;
michael@0 1670 return NS_OK;
michael@0 1671 }
michael@0 1672
michael@0 1673 //-----------------------------------------------------------------------------
michael@0 1674 // nsHttpHandler::nsIProxiedProtocolHandler
michael@0 1675 //-----------------------------------------------------------------------------
michael@0 1676
michael@0 1677 NS_IMETHODIMP
michael@0 1678 nsHttpHandler::NewProxiedChannel(nsIURI *uri,
michael@0 1679 nsIProxyInfo* givenProxyInfo,
michael@0 1680 uint32_t proxyResolveFlags,
michael@0 1681 nsIURI *proxyURI,
michael@0 1682 nsIChannel **result)
michael@0 1683 {
michael@0 1684 nsRefPtr<HttpBaseChannel> httpChannel;
michael@0 1685
michael@0 1686 LOG(("nsHttpHandler::NewProxiedChannel [proxyInfo=%p]\n",
michael@0 1687 givenProxyInfo));
michael@0 1688
michael@0 1689 nsCOMPtr<nsProxyInfo> proxyInfo;
michael@0 1690 if (givenProxyInfo) {
michael@0 1691 proxyInfo = do_QueryInterface(givenProxyInfo);
michael@0 1692 NS_ENSURE_ARG(proxyInfo);
michael@0 1693 }
michael@0 1694
michael@0 1695 bool https;
michael@0 1696 nsresult rv = uri->SchemeIs("https", &https);
michael@0 1697 if (NS_FAILED(rv))
michael@0 1698 return rv;
michael@0 1699
michael@0 1700 if (IsNeckoChild()) {
michael@0 1701 httpChannel = new HttpChannelChild();
michael@0 1702 } else {
michael@0 1703 httpChannel = new nsHttpChannel();
michael@0 1704 }
michael@0 1705
michael@0 1706 uint32_t caps = mCapabilities;
michael@0 1707
michael@0 1708 if (https) {
michael@0 1709 // enable pipelining over SSL if requested
michael@0 1710 if (mPipeliningOverSSL)
michael@0 1711 caps |= NS_HTTP_ALLOW_PIPELINING;
michael@0 1712 }
michael@0 1713
michael@0 1714 if (!IsNeckoChild()) {
michael@0 1715 // HACK: make sure PSM gets initialized on the main thread.
michael@0 1716 net_EnsurePSMInit();
michael@0 1717 }
michael@0 1718
michael@0 1719 rv = httpChannel->Init(uri, caps, proxyInfo, proxyResolveFlags, proxyURI);
michael@0 1720 if (NS_FAILED(rv))
michael@0 1721 return rv;
michael@0 1722
michael@0 1723 httpChannel.forget(result);
michael@0 1724 return NS_OK;
michael@0 1725 }
michael@0 1726
michael@0 1727 //-----------------------------------------------------------------------------
michael@0 1728 // nsHttpHandler::nsIHttpProtocolHandler
michael@0 1729 //-----------------------------------------------------------------------------
michael@0 1730
michael@0 1731 NS_IMETHODIMP
michael@0 1732 nsHttpHandler::GetUserAgent(nsACString &value)
michael@0 1733 {
michael@0 1734 value = UserAgent();
michael@0 1735 return NS_OK;
michael@0 1736 }
michael@0 1737
michael@0 1738 NS_IMETHODIMP
michael@0 1739 nsHttpHandler::GetAppName(nsACString &value)
michael@0 1740 {
michael@0 1741 value = mLegacyAppName;
michael@0 1742 return NS_OK;
michael@0 1743 }
michael@0 1744
michael@0 1745 NS_IMETHODIMP
michael@0 1746 nsHttpHandler::GetAppVersion(nsACString &value)
michael@0 1747 {
michael@0 1748 value = mLegacyAppVersion;
michael@0 1749 return NS_OK;
michael@0 1750 }
michael@0 1751
michael@0 1752 NS_IMETHODIMP
michael@0 1753 nsHttpHandler::GetPlatform(nsACString &value)
michael@0 1754 {
michael@0 1755 value = mPlatform;
michael@0 1756 return NS_OK;
michael@0 1757 }
michael@0 1758
michael@0 1759 NS_IMETHODIMP
michael@0 1760 nsHttpHandler::GetOscpu(nsACString &value)
michael@0 1761 {
michael@0 1762 value = mOscpu;
michael@0 1763 return NS_OK;
michael@0 1764 }
michael@0 1765
michael@0 1766 NS_IMETHODIMP
michael@0 1767 nsHttpHandler::GetMisc(nsACString &value)
michael@0 1768 {
michael@0 1769 value = mMisc;
michael@0 1770 return NS_OK;
michael@0 1771 }
michael@0 1772
michael@0 1773 /*static*/ void
michael@0 1774 nsHttpHandler::GetCacheSessionNameForStoragePolicy(
michael@0 1775 nsCacheStoragePolicy storagePolicy,
michael@0 1776 bool isPrivate,
michael@0 1777 uint32_t appId,
michael@0 1778 bool inBrowser,
michael@0 1779 nsACString& sessionName)
michael@0 1780 {
michael@0 1781 MOZ_ASSERT(!isPrivate || storagePolicy == nsICache::STORE_IN_MEMORY);
michael@0 1782
michael@0 1783 switch (storagePolicy) {
michael@0 1784 case nsICache::STORE_IN_MEMORY:
michael@0 1785 sessionName.AssignASCII(isPrivate ? "HTTP-memory-only-PB" : "HTTP-memory-only");
michael@0 1786 break;
michael@0 1787 case nsICache::STORE_OFFLINE:
michael@0 1788 sessionName.AssignLiteral("HTTP-offline");
michael@0 1789 break;
michael@0 1790 default:
michael@0 1791 sessionName.AssignLiteral("HTTP");
michael@0 1792 break;
michael@0 1793 }
michael@0 1794 if (appId != NECKO_NO_APP_ID || inBrowser) {
michael@0 1795 sessionName.Append('~');
michael@0 1796 sessionName.AppendInt(appId);
michael@0 1797 sessionName.Append('~');
michael@0 1798 sessionName.AppendInt(inBrowser);
michael@0 1799 }
michael@0 1800 }
michael@0 1801
michael@0 1802 //-----------------------------------------------------------------------------
michael@0 1803 // nsHttpHandler::nsIObserver
michael@0 1804 //-----------------------------------------------------------------------------
michael@0 1805
michael@0 1806 NS_IMETHODIMP
michael@0 1807 nsHttpHandler::Observe(nsISupports *subject,
michael@0 1808 const char *topic,
michael@0 1809 const char16_t *data)
michael@0 1810 {
michael@0 1811 LOG(("nsHttpHandler::Observe [topic=\"%s\"]\n", topic));
michael@0 1812
michael@0 1813 if (strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
michael@0 1814 nsCOMPtr<nsIPrefBranch> prefBranch = do_QueryInterface(subject);
michael@0 1815 if (prefBranch)
michael@0 1816 PrefsChanged(prefBranch, NS_ConvertUTF16toUTF8(data).get());
michael@0 1817 }
michael@0 1818 else if (strcmp(topic, "profile-change-net-teardown") == 0 ||
michael@0 1819 strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
michael@0 1820
michael@0 1821 mHandlerActive = false;
michael@0 1822
michael@0 1823 // clear cache of all authentication credentials.
michael@0 1824 mAuthCache.ClearAll();
michael@0 1825 mPrivateAuthCache.ClearAll();
michael@0 1826 if (mWifiTickler)
michael@0 1827 mWifiTickler->Cancel();
michael@0 1828
michael@0 1829 // ensure connection manager is shutdown
michael@0 1830 if (mConnMgr)
michael@0 1831 mConnMgr->Shutdown();
michael@0 1832
michael@0 1833 // need to reset the session start time since cache validation may
michael@0 1834 // depend on this value.
michael@0 1835 mSessionStartTime = NowInSeconds();
michael@0 1836
michael@0 1837 if (!mDoNotTrackEnabled) {
michael@0 1838 Telemetry::Accumulate(Telemetry::DNT_USAGE, DONOTTRACK_VALUE_UNSET);
michael@0 1839 }
michael@0 1840 else {
michael@0 1841 Telemetry::Accumulate(Telemetry::DNT_USAGE, mDoNotTrackValue);
michael@0 1842 }
michael@0 1843 }
michael@0 1844 else if (strcmp(topic, "profile-change-net-restore") == 0) {
michael@0 1845 // initialize connection manager
michael@0 1846 InitConnectionMgr();
michael@0 1847 }
michael@0 1848 else if (strcmp(topic, "net:clear-active-logins") == 0) {
michael@0 1849 mAuthCache.ClearAll();
michael@0 1850 mPrivateAuthCache.ClearAll();
michael@0 1851 }
michael@0 1852 else if (strcmp(topic, "net:prune-dead-connections") == 0) {
michael@0 1853 if (mConnMgr) {
michael@0 1854 mConnMgr->PruneDeadConnections();
michael@0 1855 }
michael@0 1856 }
michael@0 1857 else if (strcmp(topic, "net:prune-all-connections") == 0) {
michael@0 1858 if (mConnMgr) {
michael@0 1859 mConnMgr->DoShiftReloadConnectionCleanup(nullptr);
michael@0 1860 mConnMgr->PruneDeadConnections();
michael@0 1861 }
michael@0 1862 }
michael@0 1863 else if (strcmp(topic, "net:failed-to-process-uri-content") == 0) {
michael@0 1864 nsCOMPtr<nsIURI> uri = do_QueryInterface(subject);
michael@0 1865 if (uri && mConnMgr)
michael@0 1866 mConnMgr->ReportFailedToProcess(uri);
michael@0 1867 }
michael@0 1868 else if (strcmp(topic, "last-pb-context-exited") == 0) {
michael@0 1869 mPrivateAuthCache.ClearAll();
michael@0 1870 }
michael@0 1871
michael@0 1872 return NS_OK;
michael@0 1873 }
michael@0 1874
michael@0 1875 // nsISpeculativeConnect
michael@0 1876
michael@0 1877 NS_IMETHODIMP
michael@0 1878 nsHttpHandler::SpeculativeConnect(nsIURI *aURI,
michael@0 1879 nsIInterfaceRequestor *aCallbacks)
michael@0 1880 {
michael@0 1881 if (!mHandlerActive)
michael@0 1882 return NS_OK;
michael@0 1883
michael@0 1884 nsISiteSecurityService* sss = gHttpHandler->GetSSService();
michael@0 1885 bool isStsHost = false;
michael@0 1886 if (!sss)
michael@0 1887 return NS_OK;
michael@0 1888
michael@0 1889 nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(aCallbacks);
michael@0 1890 uint32_t flags = 0;
michael@0 1891 if (loadContext && loadContext->UsePrivateBrowsing())
michael@0 1892 flags |= nsISocketProvider::NO_PERMANENT_STORAGE;
michael@0 1893 nsCOMPtr<nsIURI> clone;
michael@0 1894 if (NS_SUCCEEDED(sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS,
michael@0 1895 aURI, flags, &isStsHost)) && isStsHost) {
michael@0 1896 if (NS_SUCCEEDED(aURI->Clone(getter_AddRefs(clone)))) {
michael@0 1897 clone->SetScheme(NS_LITERAL_CSTRING("https"));
michael@0 1898 aURI = clone.get();
michael@0 1899 }
michael@0 1900 }
michael@0 1901
michael@0 1902 nsAutoCString scheme;
michael@0 1903 nsresult rv = aURI->GetScheme(scheme);
michael@0 1904 if (NS_FAILED(rv))
michael@0 1905 return rv;
michael@0 1906
michael@0 1907 // If this is HTTPS, make sure PSM is initialized as the channel
michael@0 1908 // creation path may have been bypassed
michael@0 1909 if (scheme.EqualsLiteral("https")) {
michael@0 1910 if (!IsNeckoChild()) {
michael@0 1911 // make sure PSM gets initialized on the main thread.
michael@0 1912 net_EnsurePSMInit();
michael@0 1913 }
michael@0 1914 }
michael@0 1915 // Ensure that this is HTTP or HTTPS, otherwise we don't do preconnect here
michael@0 1916 else if (!scheme.EqualsLiteral("http"))
michael@0 1917 return NS_ERROR_UNEXPECTED;
michael@0 1918
michael@0 1919 // Construct connection info object
michael@0 1920 bool usingSSL = false;
michael@0 1921 rv = aURI->SchemeIs("https", &usingSSL);
michael@0 1922 if (NS_FAILED(rv))
michael@0 1923 return rv;
michael@0 1924
michael@0 1925 nsAutoCString host;
michael@0 1926 rv = aURI->GetAsciiHost(host);
michael@0 1927 if (NS_FAILED(rv))
michael@0 1928 return rv;
michael@0 1929
michael@0 1930 int32_t port = -1;
michael@0 1931 rv = aURI->GetPort(&port);
michael@0 1932 if (NS_FAILED(rv))
michael@0 1933 return rv;
michael@0 1934
michael@0 1935 nsAutoCString username;
michael@0 1936 aURI->GetUsername(username);
michael@0 1937
michael@0 1938 nsHttpConnectionInfo *ci =
michael@0 1939 new nsHttpConnectionInfo(host, port, username, nullptr, usingSSL);
michael@0 1940
michael@0 1941 return SpeculativeConnect(ci, aCallbacks);
michael@0 1942 }
michael@0 1943
michael@0 1944 void
michael@0 1945 nsHttpHandler::TickleWifi(nsIInterfaceRequestor *cb)
michael@0 1946 {
michael@0 1947 if (!cb || !mWifiTickler)
michael@0 1948 return;
michael@0 1949
michael@0 1950 // If B2G requires a similar mechanism nsINetworkManager, currently only avail
michael@0 1951 // on B2G, contains the necessary information on wifi and gateway
michael@0 1952
michael@0 1953 nsCOMPtr<nsIDOMWindow> domWindow;
michael@0 1954 cb->GetInterface(NS_GET_IID(nsIDOMWindow), getter_AddRefs(domWindow));
michael@0 1955 if (!domWindow)
michael@0 1956 return;
michael@0 1957
michael@0 1958 nsCOMPtr<nsIDOMNavigator> domNavigator;
michael@0 1959 domWindow->GetNavigator(getter_AddRefs(domNavigator));
michael@0 1960 nsCOMPtr<nsIMozNavigatorNetwork> networkNavigator =
michael@0 1961 do_QueryInterface(domNavigator);
michael@0 1962 if (!networkNavigator)
michael@0 1963 return;
michael@0 1964
michael@0 1965 nsCOMPtr<nsINetworkProperties> networkProperties;
michael@0 1966 networkNavigator->GetProperties(getter_AddRefs(networkProperties));
michael@0 1967 if (!networkProperties)
michael@0 1968 return;
michael@0 1969
michael@0 1970 uint32_t gwAddress;
michael@0 1971 bool isWifi;
michael@0 1972 nsresult rv;
michael@0 1973
michael@0 1974 rv = networkProperties->GetDhcpGateway(&gwAddress);
michael@0 1975 if (NS_SUCCEEDED(rv))
michael@0 1976 rv = networkProperties->GetIsWifi(&isWifi);
michael@0 1977 if (NS_FAILED(rv))
michael@0 1978 return;
michael@0 1979
michael@0 1980 if (!gwAddress || !isWifi)
michael@0 1981 return;
michael@0 1982
michael@0 1983 mWifiTickler->SetIPV4Address(gwAddress);
michael@0 1984 mWifiTickler->Tickle();
michael@0 1985 }
michael@0 1986
michael@0 1987 //-----------------------------------------------------------------------------
michael@0 1988 // nsHttpsHandler implementation
michael@0 1989 //-----------------------------------------------------------------------------
michael@0 1990
michael@0 1991 NS_IMPL_ISUPPORTS(nsHttpsHandler,
michael@0 1992 nsIHttpProtocolHandler,
michael@0 1993 nsIProxiedProtocolHandler,
michael@0 1994 nsIProtocolHandler,
michael@0 1995 nsISupportsWeakReference,
michael@0 1996 nsISpeculativeConnect)
michael@0 1997
michael@0 1998 nsresult
michael@0 1999 nsHttpsHandler::Init()
michael@0 2000 {
michael@0 2001 nsCOMPtr<nsIProtocolHandler> httpHandler(
michael@0 2002 do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http"));
michael@0 2003 MOZ_ASSERT(httpHandler.get() != nullptr);
michael@0 2004 return NS_OK;
michael@0 2005 }
michael@0 2006
michael@0 2007 NS_IMETHODIMP
michael@0 2008 nsHttpsHandler::GetScheme(nsACString &aScheme)
michael@0 2009 {
michael@0 2010 aScheme.AssignLiteral("https");
michael@0 2011 return NS_OK;
michael@0 2012 }
michael@0 2013
michael@0 2014 NS_IMETHODIMP
michael@0 2015 nsHttpsHandler::GetDefaultPort(int32_t *aPort)
michael@0 2016 {
michael@0 2017 *aPort = NS_HTTPS_DEFAULT_PORT;
michael@0 2018 return NS_OK;
michael@0 2019 }
michael@0 2020
michael@0 2021 NS_IMETHODIMP
michael@0 2022 nsHttpsHandler::GetProtocolFlags(uint32_t *aProtocolFlags)
michael@0 2023 {
michael@0 2024 *aProtocolFlags = NS_HTTP_PROTOCOL_FLAGS | URI_SAFE_TO_LOAD_IN_SECURE_CONTEXT;
michael@0 2025 return NS_OK;
michael@0 2026 }
michael@0 2027
michael@0 2028 NS_IMETHODIMP
michael@0 2029 nsHttpsHandler::NewURI(const nsACString &aSpec,
michael@0 2030 const char *aOriginCharset,
michael@0 2031 nsIURI *aBaseURI,
michael@0 2032 nsIURI **_retval)
michael@0 2033 {
michael@0 2034 return mozilla::net::NewURI(aSpec, aOriginCharset, aBaseURI, NS_HTTPS_DEFAULT_PORT, _retval);
michael@0 2035 }
michael@0 2036
michael@0 2037 NS_IMETHODIMP
michael@0 2038 nsHttpsHandler::NewChannel(nsIURI *aURI, nsIChannel **_retval)
michael@0 2039 {
michael@0 2040 MOZ_ASSERT(gHttpHandler);
michael@0 2041 if (!gHttpHandler)
michael@0 2042 return NS_ERROR_UNEXPECTED;
michael@0 2043 return gHttpHandler->NewChannel(aURI, _retval);
michael@0 2044 }
michael@0 2045
michael@0 2046 NS_IMETHODIMP
michael@0 2047 nsHttpsHandler::AllowPort(int32_t aPort, const char *aScheme, bool *_retval)
michael@0 2048 {
michael@0 2049 // don't override anything.
michael@0 2050 *_retval = false;
michael@0 2051 return NS_OK;
michael@0 2052 }
michael@0 2053
michael@0 2054 } // namespace mozilla::net
michael@0 2055 } // namespace mozilla

mercurial