Bug 1883469 [wpt PR 44910] - Document render blocking: remove "tentative" label,...
[gecko.git] / dom / security / nsHTTPSOnlyUtils.cpp
blob535efaba4ebfdb8f995016a06d1fa89cad020ef2
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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 #include "mozilla/Components.h"
8 #include "mozilla/ClearOnShutdown.h"
9 #include "mozilla/TimeStamp.h"
10 #include "mozilla/glean/GleanMetrics.h"
11 #include "mozilla/NullPrincipal.h"
12 #include "mozilla/StaticPrefs_dom.h"
13 #include "mozilla/net/DNS.h"
14 #include "nsContentUtils.h"
15 #include "nsHTTPSOnlyUtils.h"
16 #include "nsIConsoleService.h"
17 #include "nsIHttpChannel.h"
18 #include "nsIHttpChannelInternal.h"
19 #include "nsIHttpsOnlyModePermission.h"
20 #include "nsILoadInfo.h"
21 #include "nsIPermissionManager.h"
22 #include "nsIPrincipal.h"
23 #include "nsIRedirectHistoryEntry.h"
24 #include "nsIScriptError.h"
25 #include "nsIURIMutator.h"
26 #include "nsNetUtil.h"
27 #include "prnetdb.h"
29 /* static */
30 bool nsHTTPSOnlyUtils::IsHttpsOnlyModeEnabled(bool aFromPrivateWindow) {
31 // if the general pref is set to true, then we always return
32 if (mozilla::StaticPrefs::dom_security_https_only_mode()) {
33 return true;
36 // otherwise we check if executing in private browsing mode and return true
37 // if the PBM pref for HTTPS-Only is set.
38 if (aFromPrivateWindow &&
39 mozilla::StaticPrefs::dom_security_https_only_mode_pbm()) {
40 return true;
42 return false;
45 /* static */
46 bool nsHTTPSOnlyUtils::IsHttpsFirstModeEnabled(bool aFromPrivateWindow) {
47 // HTTPS-Only takes priority over HTTPS-First
48 if (IsHttpsOnlyModeEnabled(aFromPrivateWindow)) {
49 return false;
52 // if the general pref is set to true, then we always return
53 if (mozilla::StaticPrefs::dom_security_https_first()) {
54 return true;
57 // otherwise we check if executing in private browsing mode and return true
58 // if the PBM pref for HTTPS-First is set.
59 if (aFromPrivateWindow &&
60 mozilla::StaticPrefs::dom_security_https_first_pbm()) {
61 return true;
63 return false;
66 /* static */
67 void nsHTTPSOnlyUtils::PotentiallyFireHttpRequestToShortenTimout(
68 mozilla::net::DocumentLoadListener* aDocumentLoadListener) {
69 // only send http background request to counter timeouts if the
70 // pref allows us to do that.
71 if (!mozilla::StaticPrefs::
72 dom_security_https_only_mode_send_http_background_request()) {
73 return;
76 nsCOMPtr<nsIChannel> channel = aDocumentLoadListener->GetChannel();
77 if (!channel) {
78 return;
81 nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
82 bool isPrivateWin = loadInfo->GetOriginAttributes().mPrivateBrowsingId > 0;
84 // if neither HTTPS-Only nor HTTPS-First mode is enabled, then there is
85 // nothing to do here.
86 if ((!IsHttpsOnlyModeEnabled(isPrivateWin) &&
87 !IsHttpsFirstModeEnabled(isPrivateWin)) &&
88 !(loadInfo->GetWasSchemelessInput() &&
89 mozilla::StaticPrefs::dom_security_https_first_schemeless())) {
90 return;
93 // if we are not dealing with a top-level load, then there is nothing to do
94 // here.
95 if (loadInfo->GetExternalContentPolicyType() !=
96 ExtContentPolicy::TYPE_DOCUMENT) {
97 return;
100 // if the load is exempt, then there is nothing to do here.
101 uint32_t httpsOnlyStatus = loadInfo->GetHttpsOnlyStatus();
102 if (httpsOnlyStatus & nsILoadInfo::nsILoadInfo::HTTPS_ONLY_EXEMPT) {
103 return;
106 // if it's not an http channel, then there is nothing to do here.
107 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
108 if (!httpChannel) {
109 return;
112 // if it's not a GET method, then there is nothing to do here either.
113 nsAutoCString method;
114 mozilla::Unused << httpChannel->GetRequestMethod(method);
115 if (!method.EqualsLiteral("GET")) {
116 return;
119 // if it's already an https channel, then there is nothing to do here.
120 nsCOMPtr<nsIURI> channelURI;
121 channel->GetURI(getter_AddRefs(channelURI));
122 if (!channelURI->SchemeIs("http")) {
123 return;
126 // HTTPS-First only applies to standard ports but HTTPS-Only brute forces
127 // all http connections to be https and overrules HTTPS-First. In case
128 // HTTPS-First is enabled, but HTTPS-Only is not enabled, we might return
129 // early if attempting to send a background request to a non standard port.
130 if ((IsHttpsFirstModeEnabled(isPrivateWin) ||
131 (loadInfo->GetWasSchemelessInput() &&
132 mozilla::StaticPrefs::dom_security_https_first_schemeless()))) {
133 int32_t port = 0;
134 nsresult rv = channelURI->GetPort(&port);
135 int defaultPortforScheme = NS_GetDefaultPort("http");
136 if (NS_SUCCEEDED(rv) && port != defaultPortforScheme && port != -1) {
137 return;
141 // Check for general exceptions
142 if (OnionException(channelURI) || LoopbackOrLocalException(channelURI)) {
143 return;
146 RefPtr<nsIRunnable> task =
147 new TestHTTPAnswerRunnable(channelURI, aDocumentLoadListener);
148 NS_DispatchToMainThread(task.forget());
151 /* static */
152 bool nsHTTPSOnlyUtils::ShouldUpgradeRequest(nsIURI* aURI,
153 nsILoadInfo* aLoadInfo) {
154 // 1. Check if the HTTPS-Only Mode is even enabled, before we do anything else
155 bool isPrivateWin = aLoadInfo->GetOriginAttributes().mPrivateBrowsingId > 0;
156 if (!IsHttpsOnlyModeEnabled(isPrivateWin)) {
157 return false;
160 // 2. Check for general exceptions
161 if (OnionException(aURI) || LoopbackOrLocalException(aURI)) {
162 return false;
165 // 3. Check if NoUpgrade-flag is set in LoadInfo
166 uint32_t httpsOnlyStatus = aLoadInfo->GetHttpsOnlyStatus();
167 if (httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_EXEMPT) {
168 AutoTArray<nsString, 1> params = {
169 NS_ConvertUTF8toUTF16(aURI->GetSpecOrDefault())};
170 nsHTTPSOnlyUtils::LogLocalizedString("HTTPSOnlyNoUpgradeException", params,
171 nsIScriptError::infoFlag, aLoadInfo,
172 aURI);
173 return false;
176 // All subresources of an exempt triggering principal are also exempt
177 ExtContentPolicyType contentType = aLoadInfo->GetExternalContentPolicyType();
178 if (contentType != ExtContentPolicy::TYPE_DOCUMENT) {
179 if (!aLoadInfo->TriggeringPrincipal()->IsSystemPrincipal() &&
180 TestIfPrincipalIsExempt(aLoadInfo->TriggeringPrincipal())) {
181 return false;
185 // We can not upgrade "Save-As" downloads, since we have no way of detecting
186 // if the upgrade failed (Bug 1674859). For now we will just allow the
187 // download, since there will still be a visual warning about the download
188 // being insecure.
189 if (contentType == ExtContentPolicyType::TYPE_SAVEAS_DOWNLOAD) {
190 return false;
193 // We can upgrade the request - let's log it to the console
194 // Appending an 's' to the scheme for the logging. (http -> https)
195 nsAutoCString scheme;
196 aURI->GetScheme(scheme);
197 scheme.AppendLiteral("s");
198 NS_ConvertUTF8toUTF16 reportSpec(aURI->GetSpecOrDefault());
199 NS_ConvertUTF8toUTF16 reportScheme(scheme);
201 bool isSpeculative = aLoadInfo->GetExternalContentPolicyType() ==
202 ExtContentPolicy::TYPE_SPECULATIVE;
203 AutoTArray<nsString, 2> params = {reportSpec, reportScheme};
204 nsHTTPSOnlyUtils::LogLocalizedString(
205 isSpeculative ? "HTTPSOnlyUpgradeSpeculativeConnection"
206 : "HTTPSOnlyUpgradeRequest",
207 params, nsIScriptError::warningFlag, aLoadInfo, aURI);
209 // If the status was not determined before, we now indicate that the request
210 // will get upgraded, but no event-listener has been registered yet.
211 if (httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_UNINITIALIZED) {
212 httpsOnlyStatus ^= nsILoadInfo::HTTPS_ONLY_UNINITIALIZED;
213 httpsOnlyStatus |= nsILoadInfo::HTTPS_ONLY_UPGRADED_LISTENER_NOT_REGISTERED;
214 aLoadInfo->SetHttpsOnlyStatus(httpsOnlyStatus);
216 return true;
219 /* static */
220 bool nsHTTPSOnlyUtils::ShouldUpgradeWebSocket(nsIURI* aURI,
221 nsILoadInfo* aLoadInfo) {
222 // 1. Check if the HTTPS-Only Mode is even enabled, before we do anything else
223 bool isPrivateWin = aLoadInfo->GetOriginAttributes().mPrivateBrowsingId > 0;
224 if (!IsHttpsOnlyModeEnabled(isPrivateWin)) {
225 return false;
228 // 2. Check for general exceptions
229 if (OnionException(aURI) || LoopbackOrLocalException(aURI)) {
230 return false;
233 // 3. Check if NoUpgrade-flag is set in LoadInfo
234 uint32_t httpsOnlyStatus = aLoadInfo->GetHttpsOnlyStatus();
235 if (httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_EXEMPT) {
236 // Let's log to the console, that we didn't upgrade this request
237 AutoTArray<nsString, 1> params = {
238 NS_ConvertUTF8toUTF16(aURI->GetSpecOrDefault())};
239 nsHTTPSOnlyUtils::LogLocalizedString("HTTPSOnlyNoUpgradeException", params,
240 nsIScriptError::infoFlag, aLoadInfo,
241 aURI);
242 return false;
245 // All subresources of an exempt triggering principal are also exempt.
246 if (!aLoadInfo->TriggeringPrincipal()->IsSystemPrincipal() &&
247 TestIfPrincipalIsExempt(aLoadInfo->TriggeringPrincipal())) {
248 return false;
251 // We can upgrade the request - let's log it to the console
252 // Appending an 's' to the scheme for the logging. (ws -> wss)
253 nsAutoCString scheme;
254 aURI->GetScheme(scheme);
255 scheme.AppendLiteral("s");
256 NS_ConvertUTF8toUTF16 reportSpec(aURI->GetSpecOrDefault());
257 NS_ConvertUTF8toUTF16 reportScheme(scheme);
259 AutoTArray<nsString, 2> params = {reportSpec, reportScheme};
260 nsHTTPSOnlyUtils::LogLocalizedString("HTTPSOnlyUpgradeRequest", params,
261 nsIScriptError::warningFlag, aLoadInfo,
262 aURI);
263 return true;
266 /* static */
267 bool nsHTTPSOnlyUtils::IsUpgradeDowngradeEndlessLoop(
268 nsIURI* aURI, nsILoadInfo* aLoadInfo,
269 const mozilla::EnumSet<UpgradeDowngradeEndlessLoopOptions>& aOptions) {
270 // 1. Check if the HTTPS-Only/HTTPS-First is even enabled, before doing
271 // anything else
272 bool isPrivateWin = aLoadInfo->GetOriginAttributes().mPrivateBrowsingId > 0;
273 bool enforceForHTTPSOnlyMode =
274 IsHttpsOnlyModeEnabled(isPrivateWin) &&
275 aOptions.contains(
276 UpgradeDowngradeEndlessLoopOptions::EnforceForHTTPSOnlyMode);
277 bool enforceForHTTPSFirstMode =
278 IsHttpsFirstModeEnabled(isPrivateWin) &&
279 aOptions.contains(
280 UpgradeDowngradeEndlessLoopOptions::EnforceForHTTPSFirstMode);
281 bool enforceForHTTPSRR =
282 aOptions.contains(UpgradeDowngradeEndlessLoopOptions::EnforceForHTTPSRR);
283 if (!enforceForHTTPSOnlyMode && !enforceForHTTPSFirstMode &&
284 !enforceForHTTPSRR) {
285 return false;
288 // 2. Check if the upgrade downgrade pref even wants us to try to break the
289 // cycle. In the case that HTTPS RR is presented, we ignore this pref.
290 if (!mozilla::StaticPrefs::
291 dom_security_https_only_mode_break_upgrade_downgrade_endless_loop() &&
292 !enforceForHTTPSRR) {
293 return false;
296 // 3. If it's not a top-level load, then there is nothing to do here either.
297 if (aLoadInfo->GetExternalContentPolicyType() !=
298 ExtContentPolicy::TYPE_DOCUMENT) {
299 return false;
302 // 4. If the load is exempt, then it's defintely not related to https-only
303 uint32_t httpsOnlyStatus = aLoadInfo->GetHttpsOnlyStatus();
304 if ((httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_EXEMPT) &&
305 !enforceForHTTPSRR) {
306 return false;
309 // 5. If the URI to be loaded is not http, then it's defnitely no endless
310 // loop caused by https-only.
311 if (!aURI->SchemeIs("http")) {
312 return false;
315 nsAutoCString uriHost;
316 aURI->GetAsciiHost(uriHost);
318 auto uriAndPrincipalComparator = [&](nsIPrincipal* aPrincipal) {
319 nsAutoCString principalHost;
320 aPrincipal->GetAsciiHost(principalHost);
321 bool checkPath = mozilla::StaticPrefs::
322 dom_security_https_only_check_path_upgrade_downgrade_endless_loop();
323 if (!checkPath) {
324 return uriHost.Equals(principalHost);
327 nsAutoCString uriPath;
328 nsresult rv = aURI->GetFilePath(uriPath);
329 if (NS_FAILED(rv)) {
330 return false;
332 nsAutoCString principalPath;
333 aPrincipal->GetFilePath(principalPath);
334 return uriHost.Equals(principalHost) && uriPath.Equals(principalPath);
337 // 6. Check actual redirects. If the Principal that kicked off the
338 // load/redirect is not https, then it's definitely not a redirect cause by
339 // https-only. If the scheme of the principal however is https and the
340 // asciiHost of the URI to be loaded and the asciiHost of the Principal are
341 // identical, then we are dealing with an upgrade downgrade scenario and we
342 // have to break the cycle.
343 if (!aLoadInfo->RedirectChain().IsEmpty()) {
344 nsCOMPtr<nsIPrincipal> redirectPrincipal;
345 for (nsIRedirectHistoryEntry* entry : aLoadInfo->RedirectChain()) {
346 entry->GetPrincipal(getter_AddRefs(redirectPrincipal));
347 if (redirectPrincipal && redirectPrincipal->SchemeIs("https") &&
348 uriAndPrincipalComparator(redirectPrincipal)) {
349 return true;
352 } else {
353 // 6.1 We should only check if this load is triggered by a user gesture
354 // when the redirect chain is empty, since this information is only useful
355 // in our case here. When the redirect chain is not empty, this load is
356 // defnitely triggered by redirection, not a user gesture.
357 if (aLoadInfo->GetHasValidUserGestureActivation()) {
358 return false;
362 // 7. Meta redirects and JS based redirects (win.location). If the security
363 // context that triggered the load is not https, then it's defnitely no
364 // endless loop caused by https-only. If the scheme is http however and the
365 // asciiHost of the URI to be loaded matches the asciiHost of the Principal,
366 // then we are dealing with an upgrade downgrade scenario and we have to break
367 // the cycle.
368 nsCOMPtr<nsIPrincipal> triggeringPrincipal = aLoadInfo->TriggeringPrincipal();
369 if (!triggeringPrincipal->SchemeIs("https")) {
370 return false;
373 return uriAndPrincipalComparator(triggeringPrincipal);
376 /* static */
377 bool nsHTTPSOnlyUtils::ShouldUpgradeHttpsFirstRequest(nsIURI* aURI,
378 nsILoadInfo* aLoadInfo) {
379 // 1. Check if HTTPS-First Mode is enabled
380 bool isPrivateWin = aLoadInfo->GetOriginAttributes().mPrivateBrowsingId > 0;
381 if (!IsHttpsFirstModeEnabled(isPrivateWin) &&
382 !(aLoadInfo->GetWasSchemelessInput() &&
383 mozilla::StaticPrefs::dom_security_https_first_schemeless())) {
384 return false;
387 // 2. HTTPS-First only upgrades top-level loads (and speculative connections)
388 ExtContentPolicyType contentType = aLoadInfo->GetExternalContentPolicyType();
389 if (contentType != ExtContentPolicy::TYPE_DOCUMENT &&
390 contentType != ExtContentPolicy::TYPE_SPECULATIVE) {
391 return false;
394 // 3. Check for general exceptions
395 if (OnionException(aURI) || LoopbackOrLocalException(aURI)) {
396 return false;
399 // 4. Don't upgrade if upgraded previously or exempt from upgrades
400 uint32_t httpsOnlyStatus = aLoadInfo->GetHttpsOnlyStatus();
401 if (httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_UPGRADED_HTTPS_FIRST ||
402 httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_EXEMPT) {
403 return false;
406 // 5. HTTPS-First Mode only upgrades default ports - do not upgrade the
407 // request to https if port is specified and not the default port of 80.
408 MOZ_ASSERT(aURI->SchemeIs("http"), "how come the request is not 'http'?");
409 int defaultPortforScheme = NS_GetDefaultPort("http");
410 // If no port is specified, then the API returns -1 to indicate the default
411 // port.
412 int32_t port = 0;
413 nsresult rv = aURI->GetPort(&port);
414 NS_ENSURE_SUCCESS(rv, false);
415 if (port != defaultPortforScheme && port != -1) {
416 return false;
418 // 6. Do not upgrade form submissions (for now), revisit within
419 // Bug 1720500: Revisit upgrading form submissions.
420 if (aLoadInfo->GetIsFormSubmission()) {
421 return false;
424 // https-first needs to account for breaking upgrade-downgrade endless
425 // loops at this point because this function is called before we
426 // check the redirect limit in HttpBaseChannel. If we encounter
427 // a same-origin server side downgrade from e.g https://example.com
428 // to http://example.com then we simply not annotating the loadinfo
429 // and returning false from within this function. Please note that
430 // the handling for https-only mode is different from https-first mode,
431 // because https-only mode results in an exception page in case
432 // we encounter and endless upgrade downgrade loop.
433 bool isUpgradeDowngradeEndlessLoop = IsUpgradeDowngradeEndlessLoop(
434 aURI, aLoadInfo,
435 {UpgradeDowngradeEndlessLoopOptions::EnforceForHTTPSFirstMode});
436 if (isUpgradeDowngradeEndlessLoop) {
437 return false;
440 // We can upgrade the request - let's log to the console and set the status
441 // so we know that we upgraded the request.
442 if (aLoadInfo->GetWasSchemelessInput() &&
443 !IsHttpsFirstModeEnabled(isPrivateWin)) {
444 nsAutoCString urlCString;
445 aURI->GetSpec(urlCString);
446 NS_ConvertUTF8toUTF16 urlString(urlCString);
448 AutoTArray<nsString, 1> params = {urlString};
449 nsHTTPSOnlyUtils::LogLocalizedString("HTTPSFirstSchemeless", params,
450 nsIScriptError::warningFlag, aLoadInfo,
451 aURI, true);
453 mozilla::glean::httpsfirst::upgraded_schemeless.Add();
454 } else {
455 nsAutoCString scheme;
457 aURI->GetScheme(scheme);
458 scheme.AppendLiteral("s");
459 NS_ConvertUTF8toUTF16 reportSpec(aURI->GetSpecOrDefault());
460 NS_ConvertUTF8toUTF16 reportScheme(scheme);
462 bool isSpeculative = contentType == ExtContentPolicy::TYPE_SPECULATIVE;
463 AutoTArray<nsString, 2> params = {reportSpec, reportScheme};
464 nsHTTPSOnlyUtils::LogLocalizedString(
465 isSpeculative ? "HTTPSOnlyUpgradeSpeculativeConnection"
466 : "HTTPSOnlyUpgradeRequest",
467 params, nsIScriptError::warningFlag, aLoadInfo, aURI, true);
469 if (!isSpeculative) {
470 mozilla::glean::httpsfirst::upgraded.Add();
474 // Set flag so we know that we upgraded the request
475 httpsOnlyStatus |= nsILoadInfo::HTTPS_ONLY_UPGRADED_HTTPS_FIRST;
476 aLoadInfo->SetHttpsOnlyStatus(httpsOnlyStatus);
477 return true;
480 /* static */
481 already_AddRefed<nsIURI>
482 nsHTTPSOnlyUtils::PotentiallyDowngradeHttpsFirstRequest(
483 mozilla::net::DocumentLoadListener* aDocumentLoadListener,
484 nsresult aStatus) {
485 nsCOMPtr<nsIChannel> channel = aDocumentLoadListener->GetChannel();
486 nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
487 uint32_t httpsOnlyStatus = loadInfo->GetHttpsOnlyStatus();
488 // Only downgrade if we this request was upgraded using HTTPS-First Mode
489 if (!(httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_UPGRADED_HTTPS_FIRST)) {
490 return nullptr;
492 // Once loading is in progress we set that flag so that timeout counter
493 // measures do not kick in.
494 loadInfo->SetHttpsOnlyStatus(
495 httpsOnlyStatus | nsILoadInfo::HTTPS_ONLY_TOP_LEVEL_LOAD_IN_PROGRESS);
497 nsresult status = aStatus;
498 // Since 4xx and 5xx errors return NS_OK instead of NS_ERROR_*, we need
499 // to check each NS_OK for those errors.
500 // Only downgrade an NS_OK status if it is an 4xx or 5xx error.
501 if (NS_SUCCEEDED(aStatus)) {
502 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
503 // If no httpChannel exists we have nothing to do here.
504 if (!httpChannel) {
505 return nullptr;
507 uint32_t responseStatus = 0;
508 if (NS_FAILED(httpChannel->GetResponseStatus(&responseStatus))) {
509 return nullptr;
512 // In case we found one 4xx or 5xx error we need to log it later on,
513 // for that reason we flip the nsresult 'status' from 'NS_OK' to the
514 // corresponding NS_ERROR_*.
515 // To do so we convert the response status to an nsresult error
516 // Every NS_OK that is NOT an 4xx or 5xx error code won't get downgraded.
517 if (responseStatus >= 400 && responseStatus < 600) {
518 // HttpProxyResponseToErrorCode() maps 400 and 404 on
519 // the same error as a 500 status which would lead to no downgrade
520 // later on. For that reason we explicit filter for 400 and 404 status
521 // codes to log them correctly and to downgrade them if possible.
522 switch (responseStatus) {
523 case 400:
524 status = NS_ERROR_PROXY_BAD_REQUEST;
525 break;
526 case 404:
527 status = NS_ERROR_PROXY_NOT_FOUND;
528 break;
529 default:
530 status = mozilla::net::HttpProxyResponseToErrorCode(responseStatus);
531 break;
534 if (NS_SUCCEEDED(status)) {
535 return nullptr;
539 // We're only downgrading if it's possible that the error was
540 // caused by the upgrade.
541 if (HttpsUpgradeUnrelatedErrorCode(status)) {
542 return nullptr;
545 nsCOMPtr<nsIURI> uri;
546 nsresult rv = channel->GetURI(getter_AddRefs(uri));
547 NS_ENSURE_SUCCESS(rv, nullptr);
549 nsAutoCString spec;
550 nsCOMPtr<nsIURI> newURI;
552 // Only downgrade if the current scheme is (a) https or (b) view-source:https
553 if (uri->SchemeIs("https")) {
554 rv = uri->GetSpec(spec);
555 NS_ENSURE_SUCCESS(rv, nullptr);
557 rv = NS_NewURI(getter_AddRefs(newURI), spec);
558 NS_ENSURE_SUCCESS(rv, nullptr);
560 rv = NS_MutateURI(newURI).SetScheme("http"_ns).Finalize(
561 getter_AddRefs(newURI));
562 NS_ENSURE_SUCCESS(rv, nullptr);
563 } else if (uri->SchemeIs("view-source")) {
564 nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(uri);
565 if (!nestedURI) {
566 return nullptr;
568 nsCOMPtr<nsIURI> innerURI;
569 rv = nestedURI->GetInnerURI(getter_AddRefs(innerURI));
570 NS_ENSURE_SUCCESS(rv, nullptr);
571 if (!innerURI || !innerURI->SchemeIs("https")) {
572 return nullptr;
574 rv = NS_MutateURI(innerURI).SetScheme("http"_ns).Finalize(
575 getter_AddRefs(innerURI));
576 NS_ENSURE_SUCCESS(rv, nullptr);
578 nsAutoCString innerSpec;
579 rv = innerURI->GetSpec(innerSpec);
580 NS_ENSURE_SUCCESS(rv, nullptr);
582 spec.Append("view-source:");
583 spec.Append(innerSpec);
585 rv = NS_NewURI(getter_AddRefs(newURI), spec);
586 NS_ENSURE_SUCCESS(rv, nullptr);
587 } else {
588 return nullptr;
591 // Log downgrade to console
592 NS_ConvertUTF8toUTF16 reportSpec(uri->GetSpecOrDefault());
593 AutoTArray<nsString, 1> params = {reportSpec};
594 nsHTTPSOnlyUtils::LogLocalizedString("HTTPSOnlyFailedDowngradeAgain", params,
595 nsIScriptError::warningFlag, loadInfo,
596 uri, true);
598 // Record telemety
599 nsDOMNavigationTiming* timing = aDocumentLoadListener->GetTiming();
600 if (timing) {
601 mozilla::TimeStamp navigationStart = timing->GetNavigationStartTimeStamp();
602 if (navigationStart) {
603 mozilla::TimeDuration duration =
604 mozilla::TimeStamp::Now() - navigationStart;
605 bool isPrivateWin =
606 loadInfo->GetOriginAttributes().mPrivateBrowsingId > 0;
608 if (loadInfo->GetWasSchemelessInput() &&
609 !IsHttpsFirstModeEnabled(isPrivateWin)) {
610 mozilla::glean::httpsfirst::downgraded_schemeless.Add();
611 if (timing) {
612 mozilla::glean::httpsfirst::downgrade_time_schemeless
613 .AccumulateRawDuration(duration);
615 } else {
616 mozilla::glean::httpsfirst::downgraded.Add();
617 if (timing) {
618 mozilla::glean::httpsfirst::downgrade_time.AccumulateRawDuration(
619 duration);
625 return newURI.forget();
628 /* static */
629 bool nsHTTPSOnlyUtils::CouldBeHttpsOnlyError(nsIChannel* aChannel,
630 nsresult aError) {
631 // If there is no failed channel, then there is nothing to do here.
632 if (!aChannel) {
633 return false;
636 // If HTTPS-Only Mode is not enabled, then there is nothing to do here.
637 nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
638 bool isPrivateWin = loadInfo->GetOriginAttributes().mPrivateBrowsingId > 0;
639 if (!IsHttpsOnlyModeEnabled(isPrivateWin)) {
640 return false;
643 // If the load is exempt or did not get upgraded,
644 // then there is nothing to do here.
645 uint32_t httpsOnlyStatus = loadInfo->GetHttpsOnlyStatus();
646 if (httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_EXEMPT ||
647 httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_UNINITIALIZED) {
648 return false;
651 // If it's one of those errors, then most likely it's not a HTTPS-Only error
652 // (This list of errors is largely drawn from nsDocShell::DisplayLoadError())
653 return !HttpsUpgradeUnrelatedErrorCode(aError);
656 /* static */
657 bool nsHTTPSOnlyUtils::TestIfPrincipalIsExempt(nsIPrincipal* aPrincipal) {
658 static nsCOMPtr<nsIPermissionManager> sPermMgr;
659 if (!sPermMgr) {
660 sPermMgr = mozilla::components::PermissionManager::Service();
661 mozilla::ClearOnShutdown(&sPermMgr);
663 NS_ENSURE_TRUE(sPermMgr, false);
665 uint32_t perm;
666 nsresult rv = sPermMgr->TestExactPermissionFromPrincipal(
667 aPrincipal, "https-only-load-insecure"_ns, &perm);
668 NS_ENSURE_SUCCESS(rv, false);
670 return perm == nsIHttpsOnlyModePermission::LOAD_INSECURE_ALLOW ||
671 perm == nsIHttpsOnlyModePermission::LOAD_INSECURE_ALLOW_SESSION;
674 /* static */
675 void nsHTTPSOnlyUtils::TestSitePermissionAndPotentiallyAddExemption(
676 nsIChannel* aChannel) {
677 NS_ENSURE_TRUE_VOID(aChannel);
679 // If HTTPS-Only or HTTPS-First Mode is not enabled, then there is nothing to
680 // do here.
681 nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
682 bool isPrivateWin = loadInfo->GetOriginAttributes().mPrivateBrowsingId > 0;
683 bool isHttpsOnly = IsHttpsOnlyModeEnabled(isPrivateWin);
684 bool isHttpsFirst = IsHttpsFirstModeEnabled(isPrivateWin);
685 bool isSchemelessHttpsFirst =
686 (loadInfo->GetWasSchemelessInput() &&
687 mozilla::StaticPrefs::dom_security_https_first_schemeless());
688 if (!isHttpsOnly && !isHttpsFirst && !isSchemelessHttpsFirst) {
689 return;
692 // if it's not a top-level load then there is nothing to here.
693 ExtContentPolicyType type = loadInfo->GetExternalContentPolicyType();
694 if (type != ExtContentPolicy::TYPE_DOCUMENT) {
695 return;
698 // it it's not an http channel, then there is nothing to do here.
699 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
700 if (!httpChannel) {
701 return;
704 nsCOMPtr<nsIPrincipal> principal;
705 nsresult rv = nsContentUtils::GetSecurityManager()->GetChannelResultPrincipal(
706 aChannel, getter_AddRefs(principal));
707 NS_ENSURE_SUCCESS_VOID(rv);
709 uint32_t httpsOnlyStatus = loadInfo->GetHttpsOnlyStatus();
710 bool isPrincipalExempt = TestIfPrincipalIsExempt(principal);
711 if (isPrincipalExempt) {
712 httpsOnlyStatus |= nsILoadInfo::HTTPS_ONLY_EXEMPT;
713 } else {
714 // We explicitly remove the exemption flag, because this
715 // function is also consulted after redirects.
716 httpsOnlyStatus &= ~nsILoadInfo::HTTPS_ONLY_EXEMPT;
718 if (httpsOnlyStatus & nsILoadInfo::HTTPS_FIRST_EXEMPT_NEXT_LOAD &&
719 isHttpsFirst) {
720 httpsOnlyStatus &= ~nsILoadInfo::HTTPS_FIRST_EXEMPT_NEXT_LOAD;
721 httpsOnlyStatus |= nsILoadInfo::HTTPS_ONLY_EXEMPT;
723 loadInfo->SetHttpsOnlyStatus(httpsOnlyStatus);
726 /* static */
727 bool nsHTTPSOnlyUtils::IsSafeToAcceptCORSOrMixedContent(
728 nsILoadInfo* aLoadInfo) {
729 // Check if the request is exempt from upgrades
730 if ((aLoadInfo->GetHttpsOnlyStatus() & nsILoadInfo::HTTPS_ONLY_EXEMPT)) {
731 return false;
733 // Check if HTTPS-Only Mode is enabled for this request
734 bool isPrivateWin = aLoadInfo->GetOriginAttributes().mPrivateBrowsingId > 0;
735 return nsHTTPSOnlyUtils::IsHttpsOnlyModeEnabled(isPrivateWin);
738 /* static */
739 bool nsHTTPSOnlyUtils::HttpsUpgradeUnrelatedErrorCode(nsresult aError) {
740 return NS_ERROR_UNKNOWN_PROTOCOL == aError ||
741 NS_ERROR_FILE_NOT_FOUND == aError ||
742 NS_ERROR_FILE_ACCESS_DENIED == aError ||
743 NS_ERROR_UNKNOWN_HOST == aError || NS_ERROR_PHISHING_URI == aError ||
744 NS_ERROR_MALWARE_URI == aError || NS_ERROR_UNWANTED_URI == aError ||
745 NS_ERROR_HARMFUL_URI == aError || NS_ERROR_CONTENT_CRASHED == aError ||
746 NS_ERROR_FRAME_CRASHED == aError || NS_ERROR_SUPERFLUOS_AUTH == aError;
749 /* ------ Logging ------ */
751 /* static */
752 void nsHTTPSOnlyUtils::LogLocalizedString(const char* aName,
753 const nsTArray<nsString>& aParams,
754 uint32_t aFlags,
755 nsILoadInfo* aLoadInfo, nsIURI* aURI,
756 bool aUseHttpsFirst) {
757 nsAutoString logMsg;
758 nsContentUtils::FormatLocalizedString(nsContentUtils::eSECURITY_PROPERTIES,
759 aName, aParams, logMsg);
760 LogMessage(logMsg, aFlags, aLoadInfo, aURI, aUseHttpsFirst);
763 /* static */
764 void nsHTTPSOnlyUtils::LogMessage(const nsAString& aMessage, uint32_t aFlags,
765 nsILoadInfo* aLoadInfo, nsIURI* aURI,
766 bool aUseHttpsFirst) {
767 // do not log to the console if the loadinfo says we should not!
768 uint32_t httpsOnlyStatus = aLoadInfo->GetHttpsOnlyStatus();
769 if (httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_DO_NOT_LOG_TO_CONSOLE) {
770 return;
773 // Prepending HTTPS-Only to the outgoing console message
774 nsString message;
775 message.Append(aUseHttpsFirst ? u"HTTPS-First Mode: "_ns
776 : u"HTTPS-Only Mode: "_ns);
777 message.Append(aMessage);
779 // Allow for easy distinction in devtools code.
780 auto category = aUseHttpsFirst ? "HTTPSFirst"_ns : "HTTPSOnly"_ns;
782 uint64_t windowId = aLoadInfo->GetInnerWindowID();
783 if (!windowId) {
784 windowId = aLoadInfo->GetTriggeringWindowId();
786 if (windowId) {
787 // Send to content console
788 nsContentUtils::ReportToConsoleByWindowID(message, aFlags, category,
789 windowId, aURI);
790 } else {
791 // Send to browser console
792 bool isPrivateWin = aLoadInfo->GetOriginAttributes().mPrivateBrowsingId > 0;
793 nsContentUtils::LogSimpleConsoleError(message, category, isPrivateWin,
794 true /* from chrome context */,
795 aFlags);
799 /* ------ Exceptions ------ */
801 /* static */
802 bool nsHTTPSOnlyUtils::OnionException(nsIURI* aURI) {
803 // Onion-host exception can get disabled with a pref
804 if (mozilla::StaticPrefs::dom_security_https_only_mode_upgrade_onion()) {
805 return false;
807 nsAutoCString host;
808 aURI->GetHost(host);
809 return StringEndsWith(host, ".onion"_ns);
812 /* static */
813 bool nsHTTPSOnlyUtils::LoopbackOrLocalException(nsIURI* aURI) {
814 nsAutoCString asciiHost;
815 nsresult rv = aURI->GetAsciiHost(asciiHost);
816 NS_ENSURE_SUCCESS(rv, false);
818 // Let's make a quick check if the host matches these loopback strings
819 // before we do anything else
820 if (asciiHost.EqualsLiteral("localhost") || asciiHost.EqualsLiteral("::1")) {
821 return true;
824 mozilla::net::NetAddr addr;
825 if (NS_FAILED(addr.InitFromString(asciiHost))) {
826 return false;
828 // Loopback IPs are always exempt
829 if (addr.IsLoopbackAddr()) {
830 return true;
833 // Local IP exception can get disabled with a pref
834 bool upgradeLocal =
835 mozilla::StaticPrefs::dom_security_https_only_mode_upgrade_local();
836 return (!upgradeLocal && addr.IsIPAddrLocal());
839 /* static */
840 bool nsHTTPSOnlyUtils::IsEqualURIExceptSchemeAndRef(nsIURI* aHTTPSSchemeURI,
841 nsIURI* aOtherURI,
842 nsILoadInfo* aLoadInfo) {
843 // 1. Check if one of parameters is null then webpage can't be loaded yet
844 // and no further inspections are needed
845 if (!aHTTPSSchemeURI || !aOtherURI || !aLoadInfo) {
846 return false;
849 // 2. If the URI to be loaded is not http, then same origin will be detected
850 // already
851 if (!mozilla::net::SchemeIsHTTP(aOtherURI)) {
852 return false;
855 // 3. Check if the HTTPS-Only Mode is even enabled, before we do anything else
856 bool isPrivateWin = aLoadInfo->GetOriginAttributes().mPrivateBrowsingId > 0;
857 if (!IsHttpsOnlyModeEnabled(isPrivateWin) &&
858 !IsHttpsFirstModeEnabled(isPrivateWin)) {
859 return false;
862 // 4. If the load is exempt, then it's defintely not related to https-only
863 uint32_t httpsOnlyStatus = aLoadInfo->GetHttpsOnlyStatus();
864 if (httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_EXEMPT) {
865 return false;
868 // 5. Create a new target URI with 'https' instead of 'http' and compare it
869 // to the current URI
870 int32_t port = 0;
871 nsresult rv = aOtherURI->GetPort(&port);
872 NS_ENSURE_SUCCESS(rv, false);
873 // a port of -1 indicates the default port, hence we upgrade from port 80 to
874 // port 443
875 // otherwise we keep the port.
876 if (port == -1) {
877 port = NS_GetDefaultPort("https");
879 nsCOMPtr<nsIURI> newHTTPSchemeURI;
880 rv = NS_MutateURI(aOtherURI)
881 .SetScheme("https"_ns)
882 .SetPort(port)
883 .Finalize(newHTTPSchemeURI);
884 NS_ENSURE_SUCCESS(rv, false);
886 bool uriEquals = false;
887 if (NS_FAILED(
888 aHTTPSSchemeURI->EqualsExceptRef(newHTTPSchemeURI, &uriEquals))) {
889 return false;
892 return uriEquals;
894 /////////////////////////////////////////////////////////////////////
895 // Implementation of TestHTTPAnswerRunnable
897 NS_IMPL_ISUPPORTS_INHERITED(TestHTTPAnswerRunnable, mozilla::Runnable,
898 nsIStreamListener, nsIInterfaceRequestor,
899 nsITimerCallback)
901 TestHTTPAnswerRunnable::TestHTTPAnswerRunnable(
902 nsIURI* aURI, mozilla::net::DocumentLoadListener* aDocumentLoadListener)
903 : mozilla::Runnable("TestHTTPAnswerRunnable"),
904 mURI(aURI),
905 mDocumentLoadListener(aDocumentLoadListener) {}
907 /* static */
908 bool TestHTTPAnswerRunnable::IsBackgroundRequestRedirected(
909 nsIHttpChannel* aChannel) {
910 // If there is no background request (aChannel), then there is nothing
911 // to do here.
912 if (!aChannel) {
913 return false;
915 // If the request was not redirected, then there is nothing to do here.
916 nsCOMPtr<nsILoadInfo> loadinfo = aChannel->LoadInfo();
917 if (loadinfo->RedirectChain().IsEmpty()) {
918 return false;
921 // If the final URI is not targeting an https scheme, then we definitely not
922 // dealing with a 'same-origin' redirect.
923 nsCOMPtr<nsIURI> finalURI;
924 nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(finalURI));
925 NS_ENSURE_SUCCESS(rv, false);
926 if (!finalURI->SchemeIs("https")) {
927 return false;
930 // If the background request was not http, then there is nothing to do here.
931 nsCOMPtr<nsIPrincipal> firstURIPrincipal;
932 loadinfo->RedirectChain()[0]->GetPrincipal(getter_AddRefs(firstURIPrincipal));
933 if (!firstURIPrincipal || !firstURIPrincipal->SchemeIs("http")) {
934 return false;
937 // By now we have verified that the inital background request was http and
938 // that the redirected scheme is https. We want to find the following case
939 // where the background channel redirects to the https version of the
940 // top-level request.
941 // --> background channel: http://example.com
942 // |--> redirects to: https://example.com
943 // Now we have to check that the hosts are 'same-origin'.
944 nsAutoCString redirectHost;
945 nsAutoCString finalHost;
946 firstURIPrincipal->GetAsciiHost(redirectHost);
947 finalURI->GetAsciiHost(finalHost);
948 return finalHost.Equals(redirectHost);
951 NS_IMETHODIMP
952 TestHTTPAnswerRunnable::OnStartRequest(nsIRequest* aRequest) {
953 // If the request status is not OK, it means it encountered some
954 // kind of error in which case we do not want to do anything.
955 nsresult requestStatus;
956 aRequest->GetStatus(&requestStatus);
957 if (requestStatus != NS_OK) {
958 return NS_OK;
961 // Check if the original top-level channel which https-only is trying
962 // to upgrade is already in progress or if the channel is an auth channel.
963 // If it is in progress or Auth is in progress, then all good, if not
964 // then let's cancel that channel so we can dispaly the exception page.
965 nsCOMPtr<nsIChannel> docChannel = mDocumentLoadListener->GetChannel();
966 nsCOMPtr<nsIHttpChannel> httpsOnlyChannel = do_QueryInterface(docChannel);
967 if (httpsOnlyChannel) {
968 nsCOMPtr<nsILoadInfo> loadInfo = httpsOnlyChannel->LoadInfo();
969 uint32_t topLevelLoadInProgress =
970 loadInfo->GetHttpsOnlyStatus() &
971 nsILoadInfo::HTTPS_ONLY_TOP_LEVEL_LOAD_IN_PROGRESS;
973 nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal =
974 do_QueryInterface(httpsOnlyChannel);
975 bool isAuthChannel = false;
976 mozilla::Unused << httpChannelInternal->GetIsAuthChannel(&isAuthChannel);
977 // some server configurations need a long time to respond to an https
978 // connection, but also redirect any http connection to the https version of
979 // it. If the top-level load has not started yet, but the http background
980 // request redirects to https, then do not show the error page, but keep
981 // waiting for the https response of the upgraded top-level request.
982 if (!topLevelLoadInProgress) {
983 nsCOMPtr<nsIHttpChannel> backgroundHttpChannel =
984 do_QueryInterface(aRequest);
985 topLevelLoadInProgress =
986 IsBackgroundRequestRedirected(backgroundHttpChannel);
988 if (!topLevelLoadInProgress && !isAuthChannel) {
989 // Only really cancel the original top-level channel if it's
990 // status is still NS_OK, otherwise it might have already
991 // encountered some other error and was cancelled.
992 nsresult httpsOnlyChannelStatus;
993 httpsOnlyChannel->GetStatus(&httpsOnlyChannelStatus);
994 if (httpsOnlyChannelStatus == NS_OK) {
995 bool isPrivateWin =
996 loadInfo->GetOriginAttributes().mPrivateBrowsingId > 0;
997 if (!nsHTTPSOnlyUtils::IsHttpsOnlyModeEnabled(isPrivateWin)) {
998 // Record HTTPS-First Telemetry
999 if (loadInfo->GetWasSchemelessInput() &&
1000 !nsHTTPSOnlyUtils::IsHttpsFirstModeEnabled(isPrivateWin)) {
1001 mozilla::glean::httpsfirst::downgraded_on_timer_schemeless
1002 .AddToNumerator();
1003 } else {
1004 mozilla::glean::httpsfirst::downgraded_on_timer.AddToNumerator();
1008 httpsOnlyChannel->Cancel(NS_ERROR_NET_TIMEOUT_EXTERNAL);
1013 // Cancel this http request because it has reached the end of it's
1014 // lifetime at this point.
1015 aRequest->Cancel(NS_ERROR_ABORT);
1016 return NS_ERROR_ABORT;
1019 NS_IMETHODIMP
1020 TestHTTPAnswerRunnable::OnDataAvailable(nsIRequest* aRequest,
1021 nsIInputStream* aStream,
1022 uint64_t aOffset, uint32_t aCount) {
1023 // TestHTTPAnswerRunnable only cares about ::OnStartRequest which
1024 // will also cancel the request, so we should in fact never even
1025 // get here.
1026 MOZ_ASSERT(false, "how come we get to ::OnDataAvailable");
1027 return NS_OK;
1030 NS_IMETHODIMP
1031 TestHTTPAnswerRunnable::OnStopRequest(nsIRequest* aRequest,
1032 nsresult aStatusCode) {
1033 // TestHTTPAnswerRunnable only cares about ::OnStartRequest
1034 return NS_OK;
1037 NS_IMETHODIMP
1038 TestHTTPAnswerRunnable::GetInterface(const nsIID& aIID, void** aResult) {
1039 return QueryInterface(aIID, aResult);
1042 NS_IMETHODIMP
1043 TestHTTPAnswerRunnable::Run() {
1044 // Wait N milliseconds to give the original https request a heads start
1045 // before firing up this http request in the background. By default the
1046 // timer is set to 3 seconds. If the https request has not received
1047 // any signal from the server during that time, than it's almost
1048 // certain the upgraded request will result in time out.
1049 uint32_t background_timer_ms = mozilla::StaticPrefs::
1050 dom_security_https_only_fire_http_request_background_timer_ms();
1052 return NS_NewTimerWithCallback(getter_AddRefs(mTimer), this,
1053 background_timer_ms, nsITimer::TYPE_ONE_SHOT);
1056 NS_IMETHODIMP
1057 TestHTTPAnswerRunnable::Notify(nsITimer* aTimer) {
1058 if (mTimer) {
1059 mTimer->Cancel();
1060 mTimer = nullptr;
1063 // If the original channel has already started loading at this point
1064 // then there is no need to do the dance.
1065 nsCOMPtr<nsIChannel> origChannel = mDocumentLoadListener->GetChannel();
1066 nsCOMPtr<nsILoadInfo> origLoadInfo = origChannel->LoadInfo();
1067 uint32_t origHttpsOnlyStatus = origLoadInfo->GetHttpsOnlyStatus();
1068 uint32_t topLevelLoadInProgress =
1069 origHttpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_TOP_LEVEL_LOAD_IN_PROGRESS;
1070 uint32_t downloadInProgress =
1071 origHttpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_DOWNLOAD_IN_PROGRESS;
1072 if (topLevelLoadInProgress || downloadInProgress) {
1073 return NS_OK;
1076 mozilla::OriginAttributes attrs = origLoadInfo->GetOriginAttributes();
1077 RefPtr<nsIPrincipal> nullPrincipal = mozilla::NullPrincipal::Create(attrs);
1079 uint32_t loadFlags =
1080 nsIRequest::LOAD_ANONYMOUS | nsIRequest::INHIBIT_CACHING |
1081 nsIRequest::INHIBIT_PERSISTENT_CACHING | nsIRequest::LOAD_BYPASS_CACHE |
1082 nsIChannel::LOAD_BYPASS_SERVICE_WORKER;
1084 // No need to connect to the URI including the path because we only care about
1085 // the round trip time if a server responds to an http request.
1086 nsCOMPtr<nsIURI> backgroundChannelURI;
1087 nsAutoCString prePathStr;
1088 nsresult rv = mURI->GetPrePath(prePathStr);
1089 if (NS_WARN_IF(NS_FAILED(rv))) {
1090 return rv;
1092 rv = NS_NewURI(getter_AddRefs(backgroundChannelURI), prePathStr);
1093 if (NS_WARN_IF(NS_FAILED(rv))) {
1094 return rv;
1097 // we are using TYPE_OTHER because TYPE_DOCUMENT might have side effects
1098 nsCOMPtr<nsIChannel> testHTTPChannel;
1099 rv = NS_NewChannel(getter_AddRefs(testHTTPChannel), backgroundChannelURI,
1100 nullPrincipal,
1101 nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
1102 nsIContentPolicy::TYPE_OTHER, nullptr, nullptr, nullptr,
1103 nullptr, loadFlags);
1105 if (NS_WARN_IF(NS_FAILED(rv))) {
1106 return rv;
1109 // We have exempt that load from HTTPS-Only to avoid getting upgraded
1110 // to https as well. Additonally let's not log that request to the console
1111 // because it might confuse end users.
1112 nsCOMPtr<nsILoadInfo> loadInfo = testHTTPChannel->LoadInfo();
1113 uint32_t httpsOnlyStatus = loadInfo->GetHttpsOnlyStatus();
1114 httpsOnlyStatus |= nsILoadInfo::HTTPS_ONLY_EXEMPT |
1115 nsILoadInfo::HTTPS_ONLY_DO_NOT_LOG_TO_CONSOLE |
1116 nsILoadInfo::HTTPS_ONLY_BYPASS_ORB;
1117 loadInfo->SetHttpsOnlyStatus(httpsOnlyStatus);
1119 testHTTPChannel->SetNotificationCallbacks(this);
1120 testHTTPChannel->AsyncOpen(this);
1121 return NS_OK;