зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1658924: Implement HTTPS-First and automatically fall back to http if secure top-level connection is not available r=necko-reviewers,JulianWels,mattwoodrow,dragana
Differential Revision: https://phabricator.services.mozilla.com/D111686
This commit is contained in:
Родитель
c3f86167b6
Коммит
e1c35fda94
|
@ -305,6 +305,10 @@ https://127.0.0.3:433 privileged,cer
|
|||
https://badcertdomain.example.com:82 privileged,cert=badCertDomain
|
||||
https://mismatch.badcertdomain.example.com:443 privileged,cert=badCertDomain
|
||||
|
||||
# Hosts for HTTPS-First upgrades/downgrades
|
||||
http://httpsfirst.com:80 privileged
|
||||
https://httpsfirst.com:443 privileged,nocert
|
||||
|
||||
# Hosts for sha1 console warning tests
|
||||
https://sha1ee.example.com:443 privileged,cert=sha1_end_entity
|
||||
https://sha256ee.example.com:443 privileged,cert=sha256_end_entity
|
||||
|
|
|
@ -49,6 +49,7 @@ nsDocShellLoadState::nsDocShellLoadState(
|
|||
mInheritPrincipal = aLoadState.InheritPrincipal();
|
||||
mPrincipalIsExplicit = aLoadState.PrincipalIsExplicit();
|
||||
mForceAllowDataURI = aLoadState.ForceAllowDataURI();
|
||||
mIsExemptFromHTTPSOnlyMode = aLoadState.IsExemptFromHTTPSOnlyMode();
|
||||
mOriginalFrameSrc = aLoadState.OriginalFrameSrc();
|
||||
mIsFormSubmission = aLoadState.IsFormSubmission();
|
||||
mLoadType = aLoadState.LoadType();
|
||||
|
@ -103,6 +104,7 @@ nsDocShellLoadState::nsDocShellLoadState(const nsDocShellLoadState& aOther)
|
|||
mPrincipalToInherit(aOther.mPrincipalToInherit),
|
||||
mPartitionedPrincipalToInherit(aOther.mPartitionedPrincipalToInherit),
|
||||
mForceAllowDataURI(aOther.mForceAllowDataURI),
|
||||
mIsExemptFromHTTPSOnlyMode(aOther.mIsExemptFromHTTPSOnlyMode),
|
||||
mOriginalFrameSrc(aOther.mOriginalFrameSrc),
|
||||
mIsFormSubmission(aOther.mIsFormSubmission),
|
||||
mLoadType(aOther.mLoadType),
|
||||
|
@ -144,6 +146,7 @@ nsDocShellLoadState::nsDocShellLoadState(nsIURI* aURI, uint64_t aLoadIdentifier)
|
|||
mPrincipalIsExplicit(false),
|
||||
mNotifiedBeforeUnloadListeners(false),
|
||||
mForceAllowDataURI(false),
|
||||
mIsExemptFromHTTPSOnlyMode(false),
|
||||
mOriginalFrameSrc(false),
|
||||
mIsFormSubmission(false),
|
||||
mLoadType(LOAD_NORMAL),
|
||||
|
@ -486,6 +489,15 @@ void nsDocShellLoadState::SetForceAllowDataURI(bool aForceAllowDataURI) {
|
|||
mForceAllowDataURI = aForceAllowDataURI;
|
||||
}
|
||||
|
||||
bool nsDocShellLoadState::IsExemptFromHTTPSOnlyMode() const {
|
||||
return mIsExemptFromHTTPSOnlyMode;
|
||||
}
|
||||
|
||||
void nsDocShellLoadState::SetIsExemptFromHTTPSOnlyMode(
|
||||
bool aIsExemptFromHTTPSOnlyMode) {
|
||||
mIsExemptFromHTTPSOnlyMode = aIsExemptFromHTTPSOnlyMode;
|
||||
}
|
||||
|
||||
bool nsDocShellLoadState::OriginalFrameSrc() const { return mOriginalFrameSrc; }
|
||||
|
||||
void nsDocShellLoadState::SetOriginalFrameSrc(bool aOriginalFrameSrc) {
|
||||
|
@ -933,6 +945,7 @@ DocShellLoadStateInit nsDocShellLoadState::Serialize() {
|
|||
loadState.InheritPrincipal() = mInheritPrincipal;
|
||||
loadState.PrincipalIsExplicit() = mPrincipalIsExplicit;
|
||||
loadState.ForceAllowDataURI() = mForceAllowDataURI;
|
||||
loadState.IsExemptFromHTTPSOnlyMode() = mIsExemptFromHTTPSOnlyMode;
|
||||
loadState.OriginalFrameSrc() = mOriginalFrameSrc;
|
||||
loadState.IsFormSubmission() = mIsFormSubmission;
|
||||
loadState.LoadType() = mLoadType;
|
||||
|
|
|
@ -131,6 +131,10 @@ class nsDocShellLoadState final {
|
|||
|
||||
void SetForceAllowDataURI(bool aForceAllowDataURI);
|
||||
|
||||
bool IsExemptFromHTTPSOnlyMode() const;
|
||||
|
||||
void SetIsExemptFromHTTPSOnlyMode(bool aIsExemptFromHTTPSOnlyMode);
|
||||
|
||||
bool OriginalFrameSrc() const;
|
||||
|
||||
void SetOriginalFrameSrc(bool aOriginalFrameSrc);
|
||||
|
@ -404,6 +408,10 @@ class nsDocShellLoadState final {
|
|||
// to a data URI will be allowed.
|
||||
bool mForceAllowDataURI;
|
||||
|
||||
// If this attribute is true, then the top-level navigaion
|
||||
// will be exempt from HTTPS-Only-Mode upgrades.
|
||||
bool mIsExemptFromHTTPSOnlyMode;
|
||||
|
||||
// If this attribute is true, this load corresponds to a frame
|
||||
// element loading its original src (or srcdoc) attribute.
|
||||
bool mOriginalFrameSrc;
|
||||
|
|
|
@ -250,6 +250,7 @@ struct DocShellLoadStateInit
|
|||
nsIPrincipal PrincipalToInherit;
|
||||
nsIPrincipal PartitionedPrincipalToInherit;
|
||||
bool ForceAllowDataURI;
|
||||
bool IsExemptFromHTTPSOnlyMode;
|
||||
bool OriginalFrameSrc;
|
||||
bool IsFormSubmission;
|
||||
uint32_t LoadType;
|
||||
|
|
|
@ -138,6 +138,8 @@ HTTPSOnlyUpgradeRequest = Upgrading insecure request “%1$S” to use “%2$S
|
|||
HTTPSOnlyNoUpgradeException = Not upgrading insecure request “%1$S” because it is exempt.
|
||||
# LOCALIZATION NOTE: %1$S is the URL of the failed request; %2$S is an error-code.
|
||||
HTTPSOnlyFailedRequest = Upgrading insecure request “%1$S” failed. (%2$S)
|
||||
# LOCALIZATION NOTE: %S is the URL of the failed request;
|
||||
HTTPSOnlyFailedDowngradeAgain = Upgrading insecure request “%S” failed. Downgrading to “http” again.
|
||||
|
||||
# LOCALIZATION NOTE: %S is the URL of the blocked request;
|
||||
IframeSandboxBlockedDownload = Download of “%S” was blocked because the triggering iframe has the sandbox flag set.
|
||||
|
|
|
@ -44,6 +44,11 @@ bool nsHTTPSOnlyUtils::IsHttpsOnlyModeEnabled(bool aFromPrivateWindow) {
|
|||
return false;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool nsHTTPSOnlyUtils::IsHttpsFirstModeEnabled() {
|
||||
return mozilla::StaticPrefs::dom_security_https_only_mode_https_first();
|
||||
}
|
||||
|
||||
/* static */
|
||||
void nsHTTPSOnlyUtils::PotentiallyFireHttpRequestToShortenTimout(
|
||||
mozilla::net::DocumentLoadListener* aDocumentLoadListener) {
|
||||
|
@ -62,8 +67,9 @@ void nsHTTPSOnlyUtils::PotentiallyFireHttpRequestToShortenTimout(
|
|||
nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
|
||||
bool isPrivateWin = loadInfo->GetOriginAttributes().mPrivateBrowsingId > 0;
|
||||
|
||||
// if https-only mode is not even enabled, then there is nothing to do here.
|
||||
if (!IsHttpsOnlyModeEnabled(isPrivateWin)) {
|
||||
// if neither HTTPS-Only nor HTTPS-First mode is enabled, then there is
|
||||
// nothing to do here.
|
||||
if (!IsHttpsOnlyModeEnabled(isPrivateWin) && !IsHttpsFirstModeEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -213,7 +219,7 @@ bool nsHTTPSOnlyUtils::IsUpgradeDowngradeEndlessLoop(nsIURI* aURI,
|
|||
nsILoadInfo* aLoadInfo) {
|
||||
// 1. Check if the HTTPS-Only Mode is even enabled, before we do anything else
|
||||
bool isPrivateWin = aLoadInfo->GetOriginAttributes().mPrivateBrowsingId > 0;
|
||||
if (!IsHttpsOnlyModeEnabled(isPrivateWin)) {
|
||||
if (!IsHttpsOnlyModeEnabled(isPrivateWin) && !IsHttpsFirstModeEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -286,6 +292,93 @@ bool nsHTTPSOnlyUtils::IsUpgradeDowngradeEndlessLoop(nsIURI* aURI,
|
|||
return uriHost.Equals(triggeringHost);
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool nsHTTPSOnlyUtils::ShouldUpgradeHttpsFirstRequest(nsIURI* aURI,
|
||||
nsILoadInfo* aLoadInfo) {
|
||||
// 1. Check if HTTPS-First Mode is enabled
|
||||
if (!IsHttpsFirstModeEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. HTTPS-First only upgrades top-level loads
|
||||
if (aLoadInfo->GetExternalContentPolicyType() !=
|
||||
ExtContentPolicy::TYPE_DOCUMENT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3. Don't upgrade if upgraded previously or exempt from upgrades
|
||||
uint32_t httpsOnlyStatus = aLoadInfo->GetHttpsOnlyStatus();
|
||||
if (httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_UPGRADED_HTTPS_FIRST ||
|
||||
httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_EXEMPT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We can upgrade the request - let's log to the console and set the status
|
||||
// so we know that we upgraded the request.
|
||||
MOZ_ASSERT(aURI->SchemeIs("http"), "how come the request is not 'http'?");
|
||||
nsAutoCString scheme;
|
||||
aURI->GetScheme(scheme);
|
||||
scheme.AppendLiteral("s");
|
||||
NS_ConvertUTF8toUTF16 reportSpec(aURI->GetSpecOrDefault());
|
||||
NS_ConvertUTF8toUTF16 reportScheme(scheme);
|
||||
|
||||
AutoTArray<nsString, 2> params = {reportSpec, reportScheme};
|
||||
nsHTTPSOnlyUtils::LogLocalizedString("HTTPSOnlyUpgradeRequest", params,
|
||||
nsIScriptError::warningFlag, aLoadInfo,
|
||||
aURI, true);
|
||||
|
||||
// Set flag so we know that we upgraded the request
|
||||
httpsOnlyStatus |= nsILoadInfo::HTTPS_ONLY_UPGRADED_HTTPS_FIRST;
|
||||
aLoadInfo->SetHttpsOnlyStatus(httpsOnlyStatus);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */
|
||||
already_AddRefed<nsIURI>
|
||||
nsHTTPSOnlyUtils::PotentiallyDowngradeHttpsFirstRequest(nsIChannel* aChannel,
|
||||
nsresult aError) {
|
||||
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
|
||||
uint32_t httpsOnlyStatus = loadInfo->GetHttpsOnlyStatus();
|
||||
// Only downgrade if we this request was upgraded using HTTPS-First Mode
|
||||
if (!(httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_UPGRADED_HTTPS_FIRST)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// No matter if we're downgrading or not, the request failed so we need to
|
||||
// inform the background request.
|
||||
loadInfo->SetHttpsOnlyStatus(
|
||||
httpsOnlyStatus | nsILoadInfo::HTTPS_ONLY_TOP_LEVEL_LOAD_IN_PROGRESS);
|
||||
|
||||
// We're only downgrading if it's possible that the error was
|
||||
// caused by the upgrade.
|
||||
if (HttpsUpgradeUnrelatedErrorCode(aError)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsresult rv = aChannel->GetURI(getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
// Only downgrade if the current scheme is HTTPS
|
||||
if (!uri->SchemeIs("https")) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Change the scheme to http
|
||||
nsCOMPtr<nsIURI> newURI;
|
||||
mozilla::Unused << NS_MutateURI(uri).SetScheme("http"_ns).Finalize(
|
||||
getter_AddRefs(newURI));
|
||||
|
||||
// Log downgrade to console
|
||||
NS_ConvertUTF8toUTF16 reportSpec(uri->GetSpecOrDefault());
|
||||
AutoTArray<nsString, 1> params = {reportSpec};
|
||||
nsHTTPSOnlyUtils::LogLocalizedString("HTTPSOnlyFailedDowngradeAgain", params,
|
||||
nsIScriptError::warningFlag, loadInfo,
|
||||
uri, true);
|
||||
|
||||
return newURI.forget();
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool nsHTTPSOnlyUtils::CouldBeHttpsOnlyError(nsIChannel* aChannel,
|
||||
nsresult aError) {
|
||||
|
@ -311,14 +404,7 @@ bool nsHTTPSOnlyUtils::CouldBeHttpsOnlyError(nsIChannel* aChannel,
|
|||
|
||||
// If it's one of those errors, then most likely it's not a HTTPS-Only error
|
||||
// (This list of errors is largely drawn from nsDocShell::DisplayLoadError())
|
||||
return !(NS_ERROR_UNKNOWN_PROTOCOL == aError ||
|
||||
NS_ERROR_FILE_NOT_FOUND == aError ||
|
||||
NS_ERROR_FILE_ACCESS_DENIED == aError ||
|
||||
NS_ERROR_UNKNOWN_HOST == aError || NS_ERROR_PHISHING_URI == aError ||
|
||||
NS_ERROR_MALWARE_URI == aError || NS_ERROR_UNWANTED_URI == aError ||
|
||||
NS_ERROR_HARMFUL_URI == aError ||
|
||||
NS_ERROR_CONTENT_CRASHED == aError ||
|
||||
NS_ERROR_FRAME_CRASHED == aError);
|
||||
return !HttpsUpgradeUnrelatedErrorCode(aError);
|
||||
}
|
||||
|
||||
/* static */
|
||||
|
@ -391,23 +477,35 @@ bool nsHTTPSOnlyUtils::IsSafeToAcceptCORSOrMixedContent(
|
|||
return nsHTTPSOnlyUtils::IsHttpsOnlyModeEnabled(isPrivateWin);
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool nsHTTPSOnlyUtils::HttpsUpgradeUnrelatedErrorCode(nsresult aError) {
|
||||
return NS_ERROR_UNKNOWN_PROTOCOL == aError ||
|
||||
NS_ERROR_FILE_NOT_FOUND == aError ||
|
||||
NS_ERROR_FILE_ACCESS_DENIED == aError ||
|
||||
NS_ERROR_UNKNOWN_HOST == aError || NS_ERROR_PHISHING_URI == aError ||
|
||||
NS_ERROR_MALWARE_URI == aError || NS_ERROR_UNWANTED_URI == aError ||
|
||||
NS_ERROR_HARMFUL_URI == aError || NS_ERROR_CONTENT_CRASHED == aError ||
|
||||
NS_ERROR_FRAME_CRASHED == aError;
|
||||
}
|
||||
|
||||
/* ------ Logging ------ */
|
||||
|
||||
/* static */
|
||||
void nsHTTPSOnlyUtils::LogLocalizedString(const char* aName,
|
||||
const nsTArray<nsString>& aParams,
|
||||
uint32_t aFlags,
|
||||
nsILoadInfo* aLoadInfo,
|
||||
nsIURI* aURI) {
|
||||
nsILoadInfo* aLoadInfo, nsIURI* aURI,
|
||||
bool aUseHttpsFirst) {
|
||||
nsAutoString logMsg;
|
||||
nsContentUtils::FormatLocalizedString(nsContentUtils::eSECURITY_PROPERTIES,
|
||||
aName, aParams, logMsg);
|
||||
LogMessage(logMsg, aFlags, aLoadInfo, aURI);
|
||||
LogMessage(logMsg, aFlags, aLoadInfo, aURI, aUseHttpsFirst);
|
||||
}
|
||||
|
||||
/* static */
|
||||
void nsHTTPSOnlyUtils::LogMessage(const nsAString& aMessage, uint32_t aFlags,
|
||||
nsILoadInfo* aLoadInfo, nsIURI* aURI) {
|
||||
nsILoadInfo* aLoadInfo, nsIURI* aURI,
|
||||
bool aUseHttpsFirst) {
|
||||
// do not log to the console if the loadinfo says we should not!
|
||||
uint32_t httpsOnlyStatus = aLoadInfo->GetHttpsOnlyStatus();
|
||||
if (httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_DO_NOT_LOG_TO_CONSOLE) {
|
||||
|
@ -416,11 +514,12 @@ void nsHTTPSOnlyUtils::LogMessage(const nsAString& aMessage, uint32_t aFlags,
|
|||
|
||||
// Prepending HTTPS-Only to the outgoing console message
|
||||
nsString message;
|
||||
message.AppendLiteral(u"HTTPS-Only Mode: ");
|
||||
message.Append(aUseHttpsFirst ? u"HTTPS-First Mode: "_ns
|
||||
: u"HTTPS-Only Mode: "_ns);
|
||||
message.Append(aMessage);
|
||||
|
||||
// Allow for easy distinction in devtools code.
|
||||
nsCString category("HTTPSOnly");
|
||||
nsCString category(aUseHttpsFirst ? "HTTPSFirst" : "HTTPSOnly");
|
||||
|
||||
uint32_t innerWindowId = aLoadInfo->GetInnerWindowID();
|
||||
if (innerWindowId > 0) {
|
||||
|
|
|
@ -14,12 +14,18 @@
|
|||
class nsHTTPSOnlyUtils {
|
||||
public:
|
||||
/**
|
||||
* Returns if HTTPSOnly-Mode preference is enabled
|
||||
* Returns if HTTPS-Only Mode preference is enabled
|
||||
* @param aFromPrivateWindow true if executing in private browsing mode
|
||||
* @return true if HTTPS-Only Mode is enabled
|
||||
*/
|
||||
static bool IsHttpsOnlyModeEnabled(bool aFromPrivateWindow);
|
||||
|
||||
/**
|
||||
* Returns if HTTPS-First Mode preference is enabled
|
||||
* @return true if HTTPS-First Mode is enabled
|
||||
*/
|
||||
static bool IsHttpsFirstModeEnabled();
|
||||
|
||||
/**
|
||||
* Potentially fires an http request for a top-level load (provided by
|
||||
* aDocumentLoadListener) in the background to avoid long timeouts in case
|
||||
|
@ -64,8 +70,29 @@ class nsHTTPSOnlyUtils {
|
|||
nsILoadInfo* aLoadInfo);
|
||||
|
||||
/**
|
||||
* Checks if the error code is on a block-list of codes that are probably not
|
||||
* related to a HTTPS-Only Mode upgrade.
|
||||
* Determines if a request should get upgraded because of the HTTPS-First
|
||||
* mode. If true, the httpsOnlyStatus in LoadInfo gets updated and a message
|
||||
* is logged in the console.
|
||||
* @param aURI nsIURI of request
|
||||
* @param aLoadInfo nsILoadInfo of request
|
||||
* @return true if request should get upgraded
|
||||
*/
|
||||
static bool ShouldUpgradeHttpsFirstRequest(nsIURI* aURI,
|
||||
nsILoadInfo* aLoadInfo);
|
||||
|
||||
/**
|
||||
* Determines if the request was previously upgraded with HTTPS-First, creates
|
||||
* a downgraded URI and logs to console.
|
||||
* @param aError Error code
|
||||
* @param aChannel Failed channel
|
||||
* @return URI with http-scheme or nullptr
|
||||
*/
|
||||
static already_AddRefed<nsIURI> PotentiallyDowngradeHttpsFirstRequest(
|
||||
nsIChannel* aChannel, nsresult aError);
|
||||
|
||||
/**
|
||||
* Checks if the error code is on a block-list of codes that are probably
|
||||
* not related to a HTTPS-Only Mode upgrade.
|
||||
* @param aChannel The failed Channel.
|
||||
* @param aError Error Code from Request
|
||||
* @return false if error is not related to upgrade
|
||||
|
@ -74,16 +101,18 @@ class nsHTTPSOnlyUtils {
|
|||
|
||||
/**
|
||||
* Logs localized message to either content console or browser console
|
||||
* @param aName Localization key
|
||||
* @param aParams Localization parameters
|
||||
* @param aFlags Logging Flag (see nsIScriptError)
|
||||
* @param aLoadInfo The loadinfo of the request.
|
||||
* @param [aURI] Optional: URI to log
|
||||
* @param aName Localization key
|
||||
* @param aParams Localization parameters
|
||||
* @param aFlags Logging Flag (see nsIScriptError)
|
||||
* @param aLoadInfo The loadinfo of the request.
|
||||
* @param [aURI] Optional: URI to log
|
||||
* @param [aUseHttpsFirst] Optional: Log using HTTPS-First (vs. HTTPS-Only)
|
||||
*/
|
||||
static void LogLocalizedString(const char* aName,
|
||||
const nsTArray<nsString>& aParams,
|
||||
uint32_t aFlags, nsILoadInfo* aLoadInfo,
|
||||
nsIURI* aURI = nullptr);
|
||||
nsIURI* aURI = nullptr,
|
||||
bool aUseHttpsFirst = false);
|
||||
|
||||
/**
|
||||
* Tests if the HTTPS-Only upgrade exception is set for a given principal.
|
||||
|
@ -123,15 +152,24 @@ class nsHTTPSOnlyUtils {
|
|||
nsILoadInfo* aLoadInfo);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Checks if it can be ruled out that the error has something
|
||||
* to do with an HTTPS upgrade.
|
||||
* @param aError error code
|
||||
* @return true if error is unrelated to the upgrade
|
||||
*/
|
||||
static bool HttpsUpgradeUnrelatedErrorCode(nsresult aError);
|
||||
/**
|
||||
* Logs localized message to either content console or browser console
|
||||
* @param aMessage Message to log
|
||||
* @param aFlags Logging Flag (see nsIScriptError)
|
||||
* @param aLoadInfo The loadinfo of the request.
|
||||
* @param [aURI] Optional: URI to log
|
||||
* @param aMessage Message to log
|
||||
* @param aFlags Logging Flag (see nsIScriptError)
|
||||
* @param aLoadInfo The loadinfo of the request.
|
||||
* @param [aURI] Optional: URI to log
|
||||
* @param [aUseHttpsFirst] Optional: Log using HTTPS-First (vs. HTTPS-Only)
|
||||
*/
|
||||
static void LogMessage(const nsAString& aMessage, uint32_t aFlags,
|
||||
nsILoadInfo* aLoadInfo, nsIURI* aURI = nullptr);
|
||||
nsILoadInfo* aLoadInfo, nsIURI* aURI = nullptr,
|
||||
bool aUseHttpsFirst = false);
|
||||
|
||||
/**
|
||||
* Checks whether the URI ends with .onion
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
extends: ["plugin:mozilla/browser-test"],
|
||||
};
|
|
@ -0,0 +1,4 @@
|
|||
[browser_httpsfirst.js]
|
||||
support-files =
|
||||
file_httpsfirst_timeout_server.sjs
|
||||
[browser_httpsfirst_console_logging.js]
|
|
@ -0,0 +1,63 @@
|
|||
"use strict";
|
||||
|
||||
const TEST_PATH_HTTP = getRootDirectory(gTestPath).replace(
|
||||
"chrome://mochitests/content",
|
||||
"http://example.com"
|
||||
);
|
||||
|
||||
const TIMEOUT_PAGE_URI_HTTP =
|
||||
TEST_PATH_HTTP + "file_httpsfirst_timeout_server.sjs";
|
||||
|
||||
async function runPrefTest(aURI, aDesc, aAssertURLStartsWith) {
|
||||
await BrowserTestUtils.withNewTab("about:blank", async function(browser) {
|
||||
const loaded = BrowserTestUtils.browserLoaded(browser, false, null, true);
|
||||
BrowserTestUtils.loadURI(browser, aURI);
|
||||
await loaded;
|
||||
|
||||
await ContentTask.spawn(browser, { aDesc, aAssertURLStartsWith }, function({
|
||||
aDesc,
|
||||
aAssertURLStartsWith,
|
||||
}) {
|
||||
ok(
|
||||
content.document.location.href.startsWith(aAssertURLStartsWith),
|
||||
aDesc
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
add_task(async function() {
|
||||
await runPrefTest(
|
||||
"http://example.com",
|
||||
"HTTPS-First disabled; Should not upgrade",
|
||||
"http://"
|
||||
);
|
||||
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["dom.security.https_only_mode_https_first", true]],
|
||||
});
|
||||
|
||||
await runPrefTest(
|
||||
"http://example.com",
|
||||
"Should upgrade upgradeable website",
|
||||
"https://"
|
||||
);
|
||||
|
||||
await runPrefTest(
|
||||
"http://httpsfirst.com",
|
||||
"Should downgrade after error.",
|
||||
"http://"
|
||||
);
|
||||
|
||||
await runPrefTest(
|
||||
"http://domain.does.not.exist",
|
||||
"Should not downgrade on dnsNotFound error.",
|
||||
"https://"
|
||||
);
|
||||
|
||||
await runPrefTest(
|
||||
TIMEOUT_PAGE_URI_HTTP,
|
||||
"Should downgrade after timeout.",
|
||||
"http://"
|
||||
);
|
||||
});
|
|
@ -0,0 +1,71 @@
|
|||
// Bug 1658924 - HTTPS-First Mode - Tests for console logging
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1658924
|
||||
// This test makes sure that the various console messages from the HTTPS-First
|
||||
// mode get logged to the console.
|
||||
"use strict";
|
||||
|
||||
// Test Cases
|
||||
// description: Description of what the subtests expects.
|
||||
// expectLogLevel: Expected log-level of a message.
|
||||
// expectIncludes: Expected substrings the message should contain.
|
||||
let tests = [
|
||||
{
|
||||
description: "Top-Level upgrade should get logged",
|
||||
expectLogLevel: Ci.nsIConsoleMessage.warn,
|
||||
expectIncludes: ["Upgrading insecure request", "to use", "httpsfirst.com"],
|
||||
},
|
||||
{
|
||||
description: "Top-Level upgrade failure should get logged",
|
||||
expectLogLevel: Ci.nsIConsoleMessage.warn,
|
||||
expectIncludes: [
|
||||
"Upgrading insecure request",
|
||||
"failed",
|
||||
"httpsfirst.com",
|
||||
"Downgrading to",
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
add_task(async function() {
|
||||
// A longer timeout is necessary for this test than the plain mochitests
|
||||
// due to opening a new tab with the web console.
|
||||
requestLongerTimeout(4);
|
||||
|
||||
// Enable HTTPS-First Mode and register console-listener
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["dom.security.https_only_mode_https_first", true]],
|
||||
});
|
||||
Services.console.registerListener(on_new_message);
|
||||
// 1. Upgrade page to https://
|
||||
await BrowserTestUtils.loadURI(
|
||||
gBrowser.selectedBrowser,
|
||||
"http://httpsfirst.com"
|
||||
);
|
||||
|
||||
await BrowserTestUtils.waitForCondition(() => tests.length === 0);
|
||||
|
||||
// Clean up
|
||||
Services.console.unregisterListener(on_new_message);
|
||||
});
|
||||
|
||||
function on_new_message(msgObj) {
|
||||
const message = msgObj.message;
|
||||
const logLevel = msgObj.logLevel;
|
||||
|
||||
if (message.includes("HTTPS-First Mode:")) {
|
||||
for (let i = 0; i < tests.length; i++) {
|
||||
const testCase = tests[i];
|
||||
// Check if log-level matches
|
||||
if (logLevel !== testCase.expectLogLevel) {
|
||||
continue;
|
||||
}
|
||||
// Check if all substrings are included
|
||||
if (testCase.expectIncludes.some(str => !message.includes(str))) {
|
||||
continue;
|
||||
}
|
||||
ok(true, testCase.description);
|
||||
tests.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
function handleRequest(request, response)
|
||||
{
|
||||
// avoid confusing cache behaviors
|
||||
response.setHeader("Cache-Control", "no-cache", false);
|
||||
|
||||
if (request.scheme === "https") {
|
||||
// Simulating a timeout by processing the https request
|
||||
// async and *never* return anything!
|
||||
response.processAsync();
|
||||
return;
|
||||
}
|
||||
// we should never get here; just in case, return something unexpected
|
||||
response.write("do'h");
|
||||
}
|
|
@ -34,6 +34,7 @@ BROWSER_CHROME_MANIFESTS += [
|
|||
"cors/browser.ini",
|
||||
"csp/browser.ini",
|
||||
"general/browser.ini",
|
||||
"https-first/browser.ini",
|
||||
"https-only/browser.ini",
|
||||
"mixedcontentblocker/browser.ini",
|
||||
]
|
||||
|
|
|
@ -2931,6 +2931,13 @@
|
|||
value: false
|
||||
mirror: always
|
||||
|
||||
# If true, top-level request will get upgraded to HTTPS and
|
||||
# downgraded again if the request failed.
|
||||
- name: dom.security.https_only_mode_https_first
|
||||
type: RelaxedAtomicBool
|
||||
value: false
|
||||
mirror: always
|
||||
|
||||
- name: dom.security.unexpected_system_load_telemetry_enabled
|
||||
type: bool
|
||||
value: true
|
||||
|
|
|
@ -470,6 +470,12 @@ interface nsILoadInfo : nsISupports
|
|||
*/
|
||||
const unsigned long HTTPS_ONLY_DO_NOT_LOG_TO_CONSOLE = (1 << 5);
|
||||
|
||||
/**
|
||||
* This flag indicates that the request should not be logged to the
|
||||
* console.
|
||||
*/
|
||||
const unsigned long HTTPS_ONLY_UPGRADED_HTTPS_FIRST = (1 << 6);
|
||||
|
||||
/**
|
||||
* Upgrade state of HTTPS-Only Mode. The flag HTTPS_ONLY_EXEMPT can get
|
||||
* set on requests that should be excempt from an upgrade.
|
||||
|
|
|
@ -2856,7 +2856,8 @@ nsresult NS_ShouldSecureUpgrade(
|
|||
!nsMixedContentBlocker::IsPotentiallyTrustworthyLoopbackURL(aURI)) {
|
||||
if (aLoadInfo) {
|
||||
// Check if the request can get upgraded with the HTTPS-Only mode
|
||||
if (nsHTTPSOnlyUtils::ShouldUpgradeRequest(aURI, aLoadInfo)) {
|
||||
if (nsHTTPSOnlyUtils::ShouldUpgradeRequest(aURI, aLoadInfo) ||
|
||||
nsHTTPSOnlyUtils::ShouldUpgradeHttpsFirstRequest(aURI, aLoadInfo)) {
|
||||
aShouldUpgrade = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -140,6 +140,12 @@ static auto CreateDocumentLoadInfo(CanonicalBrowsingContext* aBrowsingContext,
|
|||
attrs, securityFlags, sandboxFlags);
|
||||
}
|
||||
|
||||
if (aLoadState->IsExemptFromHTTPSOnlyMode()) {
|
||||
uint32_t httpsOnlyStatus = loadInfo->GetHttpsOnlyStatus();
|
||||
httpsOnlyStatus |= nsILoadInfo::HTTPS_ONLY_EXEMPT;
|
||||
loadInfo->SetHttpsOnlyStatus(httpsOnlyStatus);
|
||||
}
|
||||
|
||||
loadInfo->SetTriggeringSandboxFlags(aLoadState->TriggeringSandboxFlags());
|
||||
loadInfo->SetHasValidUserGestureActivation(
|
||||
aLoadState->HasValidUserGestureActivation());
|
||||
|
@ -2159,6 +2165,17 @@ bool DocumentLoadListener::MaybeHandleLoadErrorWithURIFixup(nsresult aStatus) {
|
|||
mLoadStateInternalLoadFlags &
|
||||
nsDocShell::INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP,
|
||||
bc->UsePrivateBrowsing(), true, getter_AddRefs(newPostData));
|
||||
|
||||
// If the request failed, the above attempt to fix it failed but it
|
||||
// was upgraded using HTTPS-First, then let's check if we can downgrade
|
||||
// the scheme to HTTP again.
|
||||
bool isHTTPSFirstFixup = false;
|
||||
if (NS_FAILED(aStatus) && !newURI) {
|
||||
newURI = nsHTTPSOnlyUtils::PotentiallyDowngradeHttpsFirstRequest(mChannel,
|
||||
aStatus);
|
||||
isHTTPSFirstFixup = true;
|
||||
}
|
||||
|
||||
if (!newURI) {
|
||||
return false;
|
||||
}
|
||||
|
@ -2179,6 +2196,12 @@ bool DocumentLoadListener::MaybeHandleLoadErrorWithURIFixup(nsresult aStatus) {
|
|||
|
||||
loadState->SetPostDataStream(newPostData);
|
||||
|
||||
if (isHTTPSFirstFixup) {
|
||||
// We have to exempt the load from HTTPS-First to prevent a
|
||||
// upgrade-downgrade loop.
|
||||
loadState->SetIsExemptFromHTTPSOnlyMode(true);
|
||||
}
|
||||
|
||||
bc->LoadURI(loadState, false);
|
||||
return true;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче