netwerk/protocol/http/nsHttpHandler.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

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

mercurial