netwerk/protocol/http/nsHttpHandler.cpp

branch
TOR_BUG_9701
changeset 11
deefc01c0e14
equal deleted inserted replaced
-1:000000000000 0:b7c1ff15e285
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim:set ts=4 sw=4 sts=4 et cin: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 // HttpLog.h should generally be included first
8 #include "HttpLog.h"
9
10 #include "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"
51
52 #include "mozilla/net/NeckoChild.h"
53 #include "mozilla/Telemetry.h"
54
55 #if defined(XP_UNIX)
56 #include <sys/utsname.h>
57 #endif
58
59 #if defined(XP_WIN)
60 #include <windows.h>
61 #endif
62
63 #if defined(XP_MACOSX)
64 #include <CoreServices/CoreServices.h>
65 #include "nsCocoaFeatures.h"
66 #endif
67
68 //-----------------------------------------------------------------------------
69 #include "mozilla/net/HttpChannelChild.h"
70
71
72 #ifdef DEBUG
73 // defined by the socket transport service while active
74 extern PRThread *gSocketThread;
75 #endif
76
77 #define UA_PREF_PREFIX "general.useragent."
78 #ifdef XP_WIN
79 #define UA_SPARE_PLATFORM
80 #endif
81
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"
91
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
95
96 #define NS_HTTP_PROTOCOL_FLAGS (URI_STD | ALLOWS_PROXY | ALLOWS_PROXY_HTTP | URI_LOADABLE_BY_ANYONE)
97
98 //-----------------------------------------------------------------------------
99
100 namespace mozilla {
101 namespace net {
102
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);
114
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 }
121
122 *aURI = url; // no QI needed
123 return NS_OK;
124 }
125
126 //-----------------------------------------------------------------------------
127 // nsHttpHandler <public>
128 //-----------------------------------------------------------------------------
129
130 nsHttpHandler *gHttpHandler = nullptr;
131
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
212
213 LOG(("Creating nsHttpHandler [this=%p].\n", this));
214
215 RegisterStrongMemoryReporter(new SpdyZlibReporter());
216
217 MOZ_ASSERT(!gHttpHandler, "HTTP handler already created!");
218 gHttpHandler = this;
219 }
220
221 nsHttpHandler::~nsHttpHandler()
222 {
223 LOG(("Deleting nsHttpHandler [this=%p]\n", this));
224
225 // make sure the connection manager is shutdown
226 if (mConnMgr) {
227 mConnMgr->Shutdown();
228 NS_RELEASE(mConnMgr);
229 }
230
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.
233
234 nsHttp::DestroyAtomTable();
235 if (mPipelineTestTimer) {
236 mPipelineTestTimer->Cancel();
237 mPipelineTestTimer = nullptr;
238 }
239
240 gHttpHandler = nullptr;
241 }
242
243 nsresult
244 nsHttpHandler::Init()
245 {
246 nsresult rv;
247
248 LOG(("nsHttpHandler::Init\n"));
249
250 rv = nsHttp::CreateAtomTable();
251 if (NS_FAILED(rv))
252 return rv;
253
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);
260
261 if (IsNeckoChild())
262 NeckoChild::InitNeckoChild();
263
264 InitUserAgentComponents();
265
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 }
281
282 mMisc.AssignLiteral("rv:" MOZILLA_UAVERSION);
283
284 mCompatFirefox.AssignLiteral("Firefox/" MOZILLA_UAVERSION);
285
286 nsCOMPtr<nsIXULAppInfo> appInfo =
287 do_GetService("@mozilla.org/xre/app-info;1");
288
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 }
301
302 mSessionStartTime = NowInSeconds();
303 mHandlerActive = true;
304
305 rv = mAuthCache.Init();
306 if (NS_FAILED(rv)) return rv;
307
308 rv = mPrivateAuthCache.Init();
309 if (NS_FAILED(rv)) return rv;
310
311 rv = InitConnectionMgr();
312 if (NS_FAILED(rv)) return rv;
313
314 #ifdef ANDROID
315 mProductSub.AssignLiteral(MOZILLA_UAVERSION);
316 #else
317 mProductSub.AssignLiteral("20100101");
318 #endif
319
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
334
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);
340
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 }
353
354 MakeNewRequestTokenBucket();
355 mWifiTickler = new Tickler();
356 if (NS_FAILED(mWifiTickler->Init()))
357 mWifiTickler = nullptr;
358
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 }
365
366 void
367 nsHttpHandler::MakeNewRequestTokenBucket()
368 {
369 if (!mConnMgr)
370 return;
371
372 nsRefPtr<EventTokenBucket> tokenBucket =
373 new EventTokenBucket(RequestTokenBucketHz(),
374 RequestTokenBucketBurst());
375 mConnMgr->UpdateRequestTokenBucket(tokenBucket);
376 }
377
378 nsresult
379 nsHttpHandler::InitConnectionMgr()
380 {
381 nsresult rv;
382
383 if (!mConnMgr) {
384 mConnMgr = new nsHttpConnectionMgr();
385 if (!mConnMgr)
386 return NS_ERROR_OUT_OF_MEMORY;
387 NS_ADDREF(mConnMgr);
388 }
389
390 rv = mConnMgr->Init(mMaxConnections,
391 mMaxPersistentConnectionsPerServer,
392 mMaxPersistentConnectionsPerProxy,
393 mMaxRequestDelay,
394 mMaxPipelinedRequests,
395 mMaxOptimisticPipelinedRequests);
396 return rv;
397 }
398
399 nsresult
400 nsHttpHandler::AddStandardRequestHeaders(nsHttpHeaderArray *request)
401 {
402 nsresult rv;
403
404 // Add the "User-Agent" header
405 rv = request->SetHeader(nsHttp::User_Agent, UserAgent());
406 if (NS_FAILED(rv)) return rv;
407
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;
412
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 }
419
420 // Add the "Accept-Encoding" header
421 rv = request->SetHeader(nsHttp::Accept_Encoding, mAcceptEncodings);
422 if (NS_FAILED(rv)) return rv;
423
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 }
430
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 }
438
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
447
448 NS_NAMED_LITERAL_CSTRING(close, "close");
449 NS_NAMED_LITERAL_CSTRING(keepAlive, "keep-alive");
450
451 const nsACString *connectionType = &close;
452 if (caps & NS_HTTP_ALLOW_KEEPALIVE) {
453 connectionType = &keepAlive;
454 }
455
456 return request->SetHeader(nsHttp::Connection, *connectionType);
457 }
458
459 bool
460 nsHttpHandler::IsAcceptableEncoding(const char *enc)
461 {
462 if (!enc)
463 return false;
464
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;
471
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;
476
477 return nsHttp::FindToken(mAcceptEncodings.get(), enc, HTTP_LWS ",") != nullptr;
478 }
479
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 }
495
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 }
505
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 }
515
516 nsresult
517 nsHttpHandler::GetIOService(nsIIOService** result)
518 {
519 NS_ADDREF(*result = mIOService);
520 return NS_OK;
521 }
522
523 uint32_t
524 nsHttpHandler::Get32BitsOfPseudoRandom()
525 {
526 // only confirm rand seeding on socket thread
527 MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
528
529 // rand() provides different amounts of PRNG on different platforms.
530 // 15 or 31 bits are common amounts.
531
532 PR_STATIC_ASSERT(RAND_MAX >= 0xfff);
533
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 }
544
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 }
552
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();
560
561 return redirectCallbackHelper->Init(oldChan, newChan, flags);
562 }
563
564 /* static */ nsresult
565 nsHttpHandler::GenerateHostPort(const nsCString& host, int32_t port,
566 nsCString& hostLine)
567 {
568 return NS_GenerateHostPort(host, port, hostLine);
569 }
570
571 //-----------------------------------------------------------------------------
572 // nsHttpHandler <private>
573 //-----------------------------------------------------------------------------
574
575 const nsAFlatCString &
576 nsHttpHandler::UserAgent()
577 {
578 if (mUserAgentOverride) {
579 LOG(("using general.useragent.override : %s\n", mUserAgentOverride.get()));
580 return mUserAgentOverride;
581 }
582
583 if (mUserAgentIsDirty) {
584 BuildUserAgent();
585 mUserAgentIsDirty = false;
586 }
587
588 return mUserAgent;
589 }
590
591 void
592 nsHttpHandler::BuildUserAgent()
593 {
594 LOG(("nsHttpHandler::BuildUserAgent\n"));
595
596 MOZ_ASSERT(!mLegacyAppName.IsEmpty() &&
597 !mLegacyAppVersion.IsEmpty(),
598 "HTTP cannot send practical requests without this much");
599
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);
616
617 // Application portion
618 mUserAgent.Assign(mLegacyAppName);
619 mUserAgent += '/';
620 mUserAgent += mLegacyAppVersion;
621 mUserAgent += ' ';
622
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 += ')';
641
642 // Product portion
643 mUserAgent += ' ';
644 mUserAgent += mProduct;
645 mUserAgent += '/';
646 mUserAgent += mProductSub;
647
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 }
662
663 #ifdef XP_WIN
664 #define WNT_BASE "Windows NT %ld.%ld"
665 #define W64_PREFIX "; Win64"
666 #endif
667
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
685
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");
689
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
697
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;
739
740 int ret = uname(&name);
741 if (ret >= 0) {
742 nsAutoCString buf;
743 buf = (char*)name.sysname;
744
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..
752
753 buf += " i686 on x86_64";
754 } else {
755 buf += ' ';
756
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 }
768
769 mOscpu.Assign(buf);
770 }
771 #endif
772 #endif
773
774 mUserAgentIsDirty = true;
775 }
776
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.
785
786 uint32_t maxCount = nsSocketTransportService::gMaxCount;
787 if (maxCount <= 8)
788 maxCount = 1;
789 else
790 maxCount -= 8;
791
792 return maxCount;
793 }
794
795 void
796 nsHttpHandler::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
797 {
798 nsresult rv = NS_OK;
799 int32_t val;
800
801 LOG(("nsHttpHandler::PrefsChanged [pref=%s]\n", pref));
802
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))
806
807 //
808 // UA components
809 //
810
811 bool cVar = false;
812
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 }
818
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 }
825
826 //
827 // HTTP options
828 //
829
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 }
835
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 }
841
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 }
851
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 }
857
858 if (PREF_CHANGED(HTTP_PREF("max-connections"))) {
859 rv = prefs->GetIntPref(HTTP_PREF("max-connections"), &val);
860 if (NS_SUCCEEDED(rv)) {
861
862 mMaxConnections = (uint16_t) clamped((uint32_t)val,
863 (uint32_t)1, MaxSocketCount());
864
865 if (mConnMgr)
866 mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_CONNECTIONS,
867 mMaxConnections);
868 }
869 }
870
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 }
880
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 }
890
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 }
896
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 }
902
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 }
908
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 }
914
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 }
920
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 }
926
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 }
932
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 }
945
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 }
957
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 }
968
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 }
978
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 }
990
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 }
996
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));
1002 }
1003 }
1004
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;
1012 }
1013
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));
1022 }
1023 }
1024
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));
1033 }
1034 }
1035
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;
1040 }
1041
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;
1046 }
1047
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);
1052 }
1053
1054 if (PREF_CHANGED(HTTP_PREF("sendSecureXSiteReferrer"))) {
1055 rv = prefs->GetBoolPref(HTTP_PREF("sendSecureXSiteReferrer"), &cVar);
1056 if (NS_SUCCEEDED(rv))
1057 mSendSecureXSiteReferrer = cVar;
1058 }
1059
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);
1066 }
1067
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);
1074 }
1075
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;
1080 }
1081 }
1082
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);
1100 }
1101 }
1102 }
1103 }
1104 }
1105
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;
1110 }
1111 }
1112
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;
1118 }
1119
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;
1126 }
1127
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);
1132 }
1133
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;
1138 }
1139
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;
1144 }
1145
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;
1150 }
1151
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;
1156 }
1157
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;
1162 }
1163
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;
1168 }
1169
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;
1175 }
1176
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));
1181 }
1182
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);
1188 }
1189
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));
1197 }
1198
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));
1206 }
1207
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;
1213 }
1214
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)));
1221 }
1222 }
1223
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);
1230 }
1231
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;
1239 }
1240
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));
1249 }
1250
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);
1257 }
1258
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;
1265 }
1266
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();
1274 }
1275 }
1276 //
1277 // INTL options
1278 //
1279
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());
1290 }
1291 }
1292
1293 //
1294 // Tracking options
1295 //
1296
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;
1302 }
1303 }
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;
1309 }
1310 }
1311
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;
1318 }
1319 }
1320
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;
1324
1325 //
1326 // Telemetry
1327 //
1328
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;
1335 }
1336 }
1337
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;
1347 }
1348 }
1349
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);
1370 }
1371 } else {
1372 mCapabilities &= ~NS_HTTP_ALLOW_PIPELINING;
1373 if (mPipelineTestTimer) {
1374 mPipelineTestTimer->Cancel();
1375 mPipelineTestTimer = nullptr;
1376 }
1377 }
1378 }
1379 }
1380 if (requestTokenBucketUpdated) {
1381 MakeNewRequestTokenBucket();
1382 }
1383
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;
1390 }
1391 }
1392
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));
1397 }
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;
1403 }
1404 }
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;
1410 }
1411 }
1412 if (requestTokenBucketUpdated) {
1413 mRequestTokenBucket =
1414 new EventTokenBucket(RequestTokenBucketHz(),
1415 RequestTokenBucketBurst());
1416 }
1417
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;
1424 }
1425 }
1426
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.
1432 }
1433
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);
1440 }
1441
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;
1448 }
1449 }
1450
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);
1457 }
1458
1459 // Enable HTTP response timeout if TCP Keepalives are disabled.
1460 mResponseTimeoutEnabled = !mTCPKeepaliveShortLivedEnabled &&
1461 !mTCPKeepaliveLongLivedEnabled;
1462
1463 #undef PREF_CHANGED
1464 #undef MULTI_PREF_CHANGED
1465 }
1466
1467
1468 /**
1469 * Static method called by mPipelineTestTimer when it expires.
1470 */
1471 void
1472 nsHttpHandler::TimerCallback(nsITimer * aTimer, void * aClosure)
1473 {
1474 nsRefPtr<nsHttpHandler> thisObject = static_cast<nsHttpHandler*>(aClosure);
1475 if (!thisObject->mPipeliningEnabled)
1476 thisObject->mCapabilities &= ~NS_HTTP_ALLOW_PIPELINING;
1477 }
1478
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.
1485 *
1486 * Ex: passing: "en, ja"
1487 * returns: "en,ja;q=0.5"
1488 *
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)
1494 {
1495 if (!i_AcceptLanguages)
1496 return NS_OK;
1497
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;
1503
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++;
1510 }
1511
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;
1517 }
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))
1526 {
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';
1532
1533 if (*token != '\0') {
1534 comma = count_n++ != 0 ? "," : ""; // delimiter if not first item
1535 uint32_t u = QVAL_TO_UINT(q);
1536
1537 // Only display q-value if less than 1.00.
1538 if (u < 100) {
1539 const char *qval_str;
1540
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";
1549 }
1550
1551 wrote = PR_snprintf(p2, available, qval_str, comma, token, u);
1552 } else {
1553 wrote = PR_snprintf(p2, available, "%s%s", comma, token);
1554 }
1555
1556 q -= dec;
1557 p2 += wrote;
1558 available -= wrote;
1559 MOZ_ASSERT(available > 0, "allocated string not long enough");
1560 }
1561 }
1562 free(o_Accept);
1563
1564 o_AcceptLanguages.Assign((const char *) q_Accept);
1565 delete [] q_Accept;
1566
1567 return NS_OK;
1568 }
1569
1570 nsresult
1571 nsHttpHandler::SetAcceptLanguages(const char *aAcceptLanguages)
1572 {
1573 nsAutoCString buf;
1574 nsresult rv = PrepareAcceptLanguages(aAcceptLanguages, buf);
1575 if (NS_SUCCEEDED(rv))
1576 mAcceptLanguages.Assign(buf);
1577 return rv;
1578 }
1579
1580 nsresult
1581 nsHttpHandler::SetAccept(const char *aAccept)
1582 {
1583 mAccept = aAccept;
1584 return NS_OK;
1585 }
1586
1587 nsresult
1588 nsHttpHandler::SetAcceptEncodings(const char *aAcceptEncodings)
1589 {
1590 mAcceptEncodings = aAcceptEncodings;
1591 return NS_OK;
1592 }
1593
1594 //-----------------------------------------------------------------------------
1595 // nsHttpHandler::nsISupports
1596 //-----------------------------------------------------------------------------
1597
1598 NS_IMPL_ISUPPORTS(nsHttpHandler,
1599 nsIHttpProtocolHandler,
1600 nsIProxiedProtocolHandler,
1601 nsIProtocolHandler,
1602 nsIObserver,
1603 nsISupportsWeakReference,
1604 nsISpeculativeConnect)
1605
1606 //-----------------------------------------------------------------------------
1607 // nsHttpHandler::nsIProtocolHandler
1608 //-----------------------------------------------------------------------------
1609
1610 NS_IMETHODIMP
1611 nsHttpHandler::GetScheme(nsACString &aScheme)
1612 {
1613 aScheme.AssignLiteral("http");
1614 return NS_OK;
1615 }
1616
1617 NS_IMETHODIMP
1618 nsHttpHandler::GetDefaultPort(int32_t *result)
1619 {
1620 *result = NS_HTTP_DEFAULT_PORT;
1621 return NS_OK;
1622 }
1623
1624 NS_IMETHODIMP
1625 nsHttpHandler::GetProtocolFlags(uint32_t *result)
1626 {
1627 *result = NS_HTTP_PROTOCOL_FLAGS;
1628 return NS_OK;
1629 }
1630
1631 NS_IMETHODIMP
1632 nsHttpHandler::NewURI(const nsACString &aSpec,
1633 const char *aCharset,
1634 nsIURI *aBaseURI,
1635 nsIURI **aURI)
1636 {
1637 return mozilla::net::NewURI(aSpec, aCharset, aBaseURI, NS_HTTP_DEFAULT_PORT, aURI);
1638 }
1639
1640 NS_IMETHODIMP
1641 nsHttpHandler::NewChannel(nsIURI *uri, nsIChannel **result)
1642 {
1643 LOG(("nsHttpHandler::NewChannel\n"));
1644
1645 NS_ENSURE_ARG_POINTER(uri);
1646 NS_ENSURE_ARG_POINTER(result);
1647
1648 bool isHttp = false, isHttps = false;
1649
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;
1659 }
1660 }
1661
1662 return NewProxiedChannel(uri, nullptr, 0, nullptr, result);
1663 }
1664
1665 NS_IMETHODIMP
1666 nsHttpHandler::AllowPort(int32_t port, const char *scheme, bool *_retval)
1667 {
1668 // don't override anything.
1669 *_retval = false;
1670 return NS_OK;
1671 }
1672
1673 //-----------------------------------------------------------------------------
1674 // nsHttpHandler::nsIProxiedProtocolHandler
1675 //-----------------------------------------------------------------------------
1676
1677 NS_IMETHODIMP
1678 nsHttpHandler::NewProxiedChannel(nsIURI *uri,
1679 nsIProxyInfo* givenProxyInfo,
1680 uint32_t proxyResolveFlags,
1681 nsIURI *proxyURI,
1682 nsIChannel **result)
1683 {
1684 nsRefPtr<HttpBaseChannel> httpChannel;
1685
1686 LOG(("nsHttpHandler::NewProxiedChannel [proxyInfo=%p]\n",
1687 givenProxyInfo));
1688
1689 nsCOMPtr<nsProxyInfo> proxyInfo;
1690 if (givenProxyInfo) {
1691 proxyInfo = do_QueryInterface(givenProxyInfo);
1692 NS_ENSURE_ARG(proxyInfo);
1693 }
1694
1695 bool https;
1696 nsresult rv = uri->SchemeIs("https", &https);
1697 if (NS_FAILED(rv))
1698 return rv;
1699
1700 if (IsNeckoChild()) {
1701 httpChannel = new HttpChannelChild();
1702 } else {
1703 httpChannel = new nsHttpChannel();
1704 }
1705
1706 uint32_t caps = mCapabilities;
1707
1708 if (https) {
1709 // enable pipelining over SSL if requested
1710 if (mPipeliningOverSSL)
1711 caps |= NS_HTTP_ALLOW_PIPELINING;
1712 }
1713
1714 if (!IsNeckoChild()) {
1715 // HACK: make sure PSM gets initialized on the main thread.
1716 net_EnsurePSMInit();
1717 }
1718
1719 rv = httpChannel->Init(uri, caps, proxyInfo, proxyResolveFlags, proxyURI);
1720 if (NS_FAILED(rv))
1721 return rv;
1722
1723 httpChannel.forget(result);
1724 return NS_OK;
1725 }
1726
1727 //-----------------------------------------------------------------------------
1728 // nsHttpHandler::nsIHttpProtocolHandler
1729 //-----------------------------------------------------------------------------
1730
1731 NS_IMETHODIMP
1732 nsHttpHandler::GetUserAgent(nsACString &value)
1733 {
1734 value = UserAgent();
1735 return NS_OK;
1736 }
1737
1738 NS_IMETHODIMP
1739 nsHttpHandler::GetAppName(nsACString &value)
1740 {
1741 value = mLegacyAppName;
1742 return NS_OK;
1743 }
1744
1745 NS_IMETHODIMP
1746 nsHttpHandler::GetAppVersion(nsACString &value)
1747 {
1748 value = mLegacyAppVersion;
1749 return NS_OK;
1750 }
1751
1752 NS_IMETHODIMP
1753 nsHttpHandler::GetPlatform(nsACString &value)
1754 {
1755 value = mPlatform;
1756 return NS_OK;
1757 }
1758
1759 NS_IMETHODIMP
1760 nsHttpHandler::GetOscpu(nsACString &value)
1761 {
1762 value = mOscpu;
1763 return NS_OK;
1764 }
1765
1766 NS_IMETHODIMP
1767 nsHttpHandler::GetMisc(nsACString &value)
1768 {
1769 value = mMisc;
1770 return NS_OK;
1771 }
1772
1773 /*static*/ void
1774 nsHttpHandler::GetCacheSessionNameForStoragePolicy(
1775 nsCacheStoragePolicy storagePolicy,
1776 bool isPrivate,
1777 uint32_t appId,
1778 bool inBrowser,
1779 nsACString& sessionName)
1780 {
1781 MOZ_ASSERT(!isPrivate || storagePolicy == nsICache::STORE_IN_MEMORY);
1782
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;
1793 }
1794 if (appId != NECKO_NO_APP_ID || inBrowser) {
1795 sessionName.Append('~');
1796 sessionName.AppendInt(appId);
1797 sessionName.Append('~');
1798 sessionName.AppendInt(inBrowser);
1799 }
1800 }
1801
1802 //-----------------------------------------------------------------------------
1803 // nsHttpHandler::nsIObserver
1804 //-----------------------------------------------------------------------------
1805
1806 NS_IMETHODIMP
1807 nsHttpHandler::Observe(nsISupports *subject,
1808 const char *topic,
1809 const char16_t *data)
1810 {
1811 LOG(("nsHttpHandler::Observe [topic=\"%s\"]\n", topic));
1812
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());
1817 }
1818 else if (strcmp(topic, "profile-change-net-teardown") == 0 ||
1819 strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
1820
1821 mHandlerActive = false;
1822
1823 // clear cache of all authentication credentials.
1824 mAuthCache.ClearAll();
1825 mPrivateAuthCache.ClearAll();
1826 if (mWifiTickler)
1827 mWifiTickler->Cancel();
1828
1829 // ensure connection manager is shutdown
1830 if (mConnMgr)
1831 mConnMgr->Shutdown();
1832
1833 // need to reset the session start time since cache validation may
1834 // depend on this value.
1835 mSessionStartTime = NowInSeconds();
1836
1837 if (!mDoNotTrackEnabled) {
1838 Telemetry::Accumulate(Telemetry::DNT_USAGE, DONOTTRACK_VALUE_UNSET);
1839 }
1840 else {
1841 Telemetry::Accumulate(Telemetry::DNT_USAGE, mDoNotTrackValue);
1842 }
1843 }
1844 else if (strcmp(topic, "profile-change-net-restore") == 0) {
1845 // initialize connection manager
1846 InitConnectionMgr();
1847 }
1848 else if (strcmp(topic, "net:clear-active-logins") == 0) {
1849 mAuthCache.ClearAll();
1850 mPrivateAuthCache.ClearAll();
1851 }
1852 else if (strcmp(topic, "net:prune-dead-connections") == 0) {
1853 if (mConnMgr) {
1854 mConnMgr->PruneDeadConnections();
1855 }
1856 }
1857 else if (strcmp(topic, "net:prune-all-connections") == 0) {
1858 if (mConnMgr) {
1859 mConnMgr->DoShiftReloadConnectionCleanup(nullptr);
1860 mConnMgr->PruneDeadConnections();
1861 }
1862 }
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);
1867 }
1868 else if (strcmp(topic, "last-pb-context-exited") == 0) {
1869 mPrivateAuthCache.ClearAll();
1870 }
1871
1872 return NS_OK;
1873 }
1874
1875 // nsISpeculativeConnect
1876
1877 NS_IMETHODIMP
1878 nsHttpHandler::SpeculativeConnect(nsIURI *aURI,
1879 nsIInterfaceRequestor *aCallbacks)
1880 {
1881 if (!mHandlerActive)
1882 return NS_OK;
1883
1884 nsISiteSecurityService* sss = gHttpHandler->GetSSService();
1885 bool isStsHost = false;
1886 if (!sss)
1887 return NS_OK;
1888
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();
1899 }
1900 }
1901
1902 nsAutoCString scheme;
1903 nsresult rv = aURI->GetScheme(scheme);
1904 if (NS_FAILED(rv))
1905 return rv;
1906
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();
1913 }
1914 }
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;
1918
1919 // Construct connection info object
1920 bool usingSSL = false;
1921 rv = aURI->SchemeIs("https", &usingSSL);
1922 if (NS_FAILED(rv))
1923 return rv;
1924
1925 nsAutoCString host;
1926 rv = aURI->GetAsciiHost(host);
1927 if (NS_FAILED(rv))
1928 return rv;
1929
1930 int32_t port = -1;
1931 rv = aURI->GetPort(&port);
1932 if (NS_FAILED(rv))
1933 return rv;
1934
1935 nsAutoCString username;
1936 aURI->GetUsername(username);
1937
1938 nsHttpConnectionInfo *ci =
1939 new nsHttpConnectionInfo(host, port, username, nullptr, usingSSL);
1940
1941 return SpeculativeConnect(ci, aCallbacks);
1942 }
1943
1944 void
1945 nsHttpHandler::TickleWifi(nsIInterfaceRequestor *cb)
1946 {
1947 if (!cb || !mWifiTickler)
1948 return;
1949
1950 // If B2G requires a similar mechanism nsINetworkManager, currently only avail
1951 // on B2G, contains the necessary information on wifi and gateway
1952
1953 nsCOMPtr<nsIDOMWindow> domWindow;
1954 cb->GetInterface(NS_GET_IID(nsIDOMWindow), getter_AddRefs(domWindow));
1955 if (!domWindow)
1956 return;
1957
1958 nsCOMPtr<nsIDOMNavigator> domNavigator;
1959 domWindow->GetNavigator(getter_AddRefs(domNavigator));
1960 nsCOMPtr<nsIMozNavigatorNetwork> networkNavigator =
1961 do_QueryInterface(domNavigator);
1962 if (!networkNavigator)
1963 return;
1964
1965 nsCOMPtr<nsINetworkProperties> networkProperties;
1966 networkNavigator->GetProperties(getter_AddRefs(networkProperties));
1967 if (!networkProperties)
1968 return;
1969
1970 uint32_t gwAddress;
1971 bool isWifi;
1972 nsresult rv;
1973
1974 rv = networkProperties->GetDhcpGateway(&gwAddress);
1975 if (NS_SUCCEEDED(rv))
1976 rv = networkProperties->GetIsWifi(&isWifi);
1977 if (NS_FAILED(rv))
1978 return;
1979
1980 if (!gwAddress || !isWifi)
1981 return;
1982
1983 mWifiTickler->SetIPV4Address(gwAddress);
1984 mWifiTickler->Tickle();
1985 }
1986
1987 //-----------------------------------------------------------------------------
1988 // nsHttpsHandler implementation
1989 //-----------------------------------------------------------------------------
1990
1991 NS_IMPL_ISUPPORTS(nsHttpsHandler,
1992 nsIHttpProtocolHandler,
1993 nsIProxiedProtocolHandler,
1994 nsIProtocolHandler,
1995 nsISupportsWeakReference,
1996 nsISpeculativeConnect)
1997
1998 nsresult
1999 nsHttpsHandler::Init()
2000 {
2001 nsCOMPtr<nsIProtocolHandler> httpHandler(
2002 do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http"));
2003 MOZ_ASSERT(httpHandler.get() != nullptr);
2004 return NS_OK;
2005 }
2006
2007 NS_IMETHODIMP
2008 nsHttpsHandler::GetScheme(nsACString &aScheme)
2009 {
2010 aScheme.AssignLiteral("https");
2011 return NS_OK;
2012 }
2013
2014 NS_IMETHODIMP
2015 nsHttpsHandler::GetDefaultPort(int32_t *aPort)
2016 {
2017 *aPort = NS_HTTPS_DEFAULT_PORT;
2018 return NS_OK;
2019 }
2020
2021 NS_IMETHODIMP
2022 nsHttpsHandler::GetProtocolFlags(uint32_t *aProtocolFlags)
2023 {
2024 *aProtocolFlags = NS_HTTP_PROTOCOL_FLAGS | URI_SAFE_TO_LOAD_IN_SECURE_CONTEXT;
2025 return NS_OK;
2026 }
2027
2028 NS_IMETHODIMP
2029 nsHttpsHandler::NewURI(const nsACString &aSpec,
2030 const char *aOriginCharset,
2031 nsIURI *aBaseURI,
2032 nsIURI **_retval)
2033 {
2034 return mozilla::net::NewURI(aSpec, aOriginCharset, aBaseURI, NS_HTTPS_DEFAULT_PORT, _retval);
2035 }
2036
2037 NS_IMETHODIMP
2038 nsHttpsHandler::NewChannel(nsIURI *aURI, nsIChannel **_retval)
2039 {
2040 MOZ_ASSERT(gHttpHandler);
2041 if (!gHttpHandler)
2042 return NS_ERROR_UNEXPECTED;
2043 return gHttpHandler->NewChannel(aURI, _retval);
2044 }
2045
2046 NS_IMETHODIMP
2047 nsHttpsHandler::AllowPort(int32_t aPort, const char *aScheme, bool *_retval)
2048 {
2049 // don't override anything.
2050 *_retval = false;
2051 return NS_OK;
2052 }
2053
2054 } // namespace mozilla::net
2055 } // namespace mozilla

mercurial