diff --git a/netwerk/base/nsDNSPrefetch.cpp b/netwerk/base/nsDNSPrefetch.cpp index 96df503d89d0..efe84c95b21f 100644 --- a/netwerk/base/nsDNSPrefetch.cpp +++ b/netwerk/base/nsDNSPrefetch.cpp @@ -80,41 +80,7 @@ nsresult nsDNSPrefetch::PrefetchHigh(bool refreshDNS) { return Prefetch(refreshDNS ? nsIDNSService::RESOLVE_BYPASS_CACHE : 0); } -namespace { - -class HTTPSRRListener final : public nsIDNSListener { - public: - NS_DECL_THREADSAFE_ISUPPORTS - NS_DECL_NSIDNSLISTENER - - explicit HTTPSRRListener( - std::function&& aCallback) - : mResultCallback(std::move(aCallback)) {} - - private: - ~HTTPSRRListener() = default; - std::function mResultCallback; -}; - -NS_IMPL_ISUPPORTS(HTTPSRRListener, nsIDNSListener) - -NS_IMETHODIMP -HTTPSRRListener::OnLookupComplete(nsICancelable* aRequest, nsIDNSRecord* aRec, - nsresult aStatus) { - if (NS_FAILED(aStatus)) { - mResultCallback(nullptr); - return NS_OK; - } - - nsCOMPtr httpsRecord = do_QueryInterface(aRec); - mResultCallback(httpsRecord); - return NS_OK; -} - -}; // namespace - -nsresult nsDNSPrefetch::FetchHTTPSSVC( - bool aRefreshDNS, std::function&& aCallback) { +nsresult nsDNSPrefetch::FetchHTTPSSVC(bool aRefreshDNS) { if (!sDNSService) { return NS_ERROR_NOT_AVAILABLE; } @@ -127,9 +93,8 @@ nsresult nsDNSPrefetch::FetchHTTPSSVC( } nsCOMPtr tmpOutstanding; - nsCOMPtr listener = new HTTPSRRListener(std::move(aCallback)); return sDNSService->AsyncResolveNative( - mHostname, nsIDNSService::RESOLVE_TYPE_HTTPSSVC, flags, nullptr, listener, + mHostname, nsIDNSService::RESOLVE_TYPE_HTTPSSVC, flags, nullptr, this, target, mOriginAttributes, getter_AddRefs(tmpOutstanding)); } @@ -138,7 +103,9 @@ NS_IMPL_ISUPPORTS(nsDNSPrefetch, nsIDNSListener) NS_IMETHODIMP nsDNSPrefetch::OnLookupComplete(nsICancelable* request, nsIDNSRecord* rec, nsresult status) { - if (mStoreTiming) { + nsCOMPtr httpsRecord = do_QueryInterface(rec); + + if (mStoreTiming && !httpsRecord) { mEndTimestamp = mozilla::TimeStamp::Now(); } nsCOMPtr listener = do_QueryReferent(mListener); diff --git a/netwerk/base/nsDNSPrefetch.h b/netwerk/base/nsDNSPrefetch.h index 44d7301f4289..abb8404ea462 100644 --- a/netwerk/base/nsDNSPrefetch.h +++ b/netwerk/base/nsDNSPrefetch.h @@ -6,8 +6,6 @@ #ifndef nsDNSPrefetch_h___ #define nsDNSPrefetch_h___ -#include - #include "nsIWeakReferenceUtils.h" #include "nsString.h" #include "mozilla/TimeStamp.h" @@ -46,8 +44,7 @@ class nsDNSPrefetch final : public nsIDNSListener { nsresult PrefetchMedium(bool refreshDNS = false); nsresult PrefetchLow(bool refreshDNS = false); - nsresult FetchHTTPSSVC( - bool aRefreshDNS, std::function&& aCallback); + nsresult FetchHTTPSSVC(bool aRefreshDNS); private: nsCString mHostname; diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index 61b4aaf12980..6b7d1e4f7a14 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -572,7 +572,16 @@ nsresult nsHttpChannel::OnBeforeConnect() { auto resultCallback = [self(self)](bool aResult, nsresult aStatus) { MOZ_ASSERT(NS_IsMainThread()); - nsresult rv = self->MaybeUseHTTPSRRForUpgrade(aResult, aStatus); + // We need to wait for HTTPSSVC record if there is no AltSvc or HSTS + // upgrade for this request. + if (!aResult && NS_SUCCEEDED(aStatus) && self->LoadUseHTTPSSVC()) { + LOG(("nsHttpChannel Wait for HTTPSSVC record [this=%p]\n", + self.get())); + self->StoreWaitHTTPSSVCRecord(true); + return; + } + + nsresult rv = self->ContinueOnBeforeConnect(aResult, aStatus); if (NS_FAILED(rv)) { self->CloseCacheEntry(false); Unused << self->AsyncAbort(rv); @@ -609,30 +618,7 @@ nsresult nsHttpChannel::OnBeforeConnect() { } } - return MaybeUseHTTPSRRForUpgrade(shouldUpgrade, NS_OK); -} - -nsresult nsHttpChannel::MaybeUseHTTPSRRForUpgrade(bool aShouldUpgrade, - nsresult aStatus) { - if (NS_FAILED(aStatus)) { - return aStatus; - } - - if (mURI->SchemeIs("https") || aShouldUpgrade || !LoadUseHTTPSSVC()) { - return ContinueOnBeforeConnect(aShouldUpgrade, aStatus); - } - - if (mHTTPSSVCRecord) { - LOG(("nsHttpChannel::MaybeUseHTTPSRRForUpgrade [%p] already got HTTPS RR", - this)); - StoreWaitHTTPSSVCRecord(false); - return ContinueOnBeforeConnect(true, aStatus); - } - - LOG(("nsHttpChannel::MaybeUseHTTPSRRForUpgrade [%p] wait for HTTPS RR", - this)); - StoreWaitHTTPSSVCRecord(true); - return NS_OK; + return ContinueOnBeforeConnect(shouldUpgrade, NS_OK); } nsresult nsHttpChannel::ContinueOnBeforeConnect(bool aShouldUpgrade, @@ -642,8 +628,6 @@ nsresult nsHttpChannel::ContinueOnBeforeConnect(bool aShouldUpgrade, "[this=%p aShouldUpgrade=%d rv=%" PRIx32 "]\n", this, aShouldUpgrade, static_cast(aStatus))); - MOZ_ASSERT(!LoadWaitHTTPSSVCRecord()); - if (NS_FAILED(aStatus)) { return aStatus; } @@ -6833,12 +6817,6 @@ nsresult nsHttpChannel::BeginConnect() { } nsresult nsHttpChannel::MaybeStartDNSPrefetch() { - bool httpssvcQueried = false; - // If https rr is not queried sucessfully, we have to reset mUseHTTPSSVC to - // false. Otherwise, this channel may wait https rr forever. - auto resetUsHTTPSSVC = - MakeScopeExit([&] { StoreUseHTTPSSVC(httpssvcQueried); }); - // Start a DNS lookup very early in case the real open is queued the DNS can // happen in parallel. Do not do so in the presence of an HTTP proxy as // all lookups other than for the proxy itself are done by the proxy. @@ -6889,22 +6867,10 @@ nsresult nsHttpChannel::MaybeStartDNSPrefetch() { if (LoadUseHTTPSSVC() || gHttpHandler->UseHTTPSRRForSpeculativeConnection()) { - nsWeakPtr weakPtrThis( - do_GetWeakReference(static_cast(this))); - rv = mDNSPrefetch->FetchHTTPSSVC( - mCaps & NS_HTTP_REFRESH_DNS, - [weakPtrThis](nsIDNSHTTPSSVCRecord* aRecord) { - nsCOMPtr channel = do_QueryReferent(weakPtrThis); - RefPtr httpChannelImpl = do_QueryObject(channel); - if (httpChannelImpl) { - httpChannelImpl->OnHTTPSRRAvailable(aRecord); - } - }); + rv = mDNSPrefetch->FetchHTTPSSVC(mCaps & NS_HTTP_REFRESH_DNS); if (NS_FAILED(rv)) { LOG((" FetchHTTPSSVC failed with 0x%08" PRIx32, static_cast(rv))); - } else { - httpssvcQueried = true; } } } @@ -9041,72 +9007,52 @@ nsHttpChannel::OnLookupComplete(nsICancelable* request, nsIDNSRecord* rec, nsresult status) { MOZ_ASSERT(NS_IsMainThread(), "Expecting DNS callback on main thread."); + nsCOMPtr httpSSVCRecord = do_QueryInterface(rec); LOG( ("nsHttpChannel::OnLookupComplete [this=%p] prefetch complete%s: " - "%s status[0x%" PRIx32 "]\n", + "%s status[0x%" PRIx32 "], isHTTPSSVC=%d\n", this, mCaps & NS_HTTP_REFRESH_DNS ? ", refresh requested" : "", NS_SUCCEEDED(status) ? "success" : "failure", - static_cast(status))); + static_cast(status), !!httpSSVCRecord)); - // We no longer need the dns prefetch object. Note: mDNSPrefetch could be - // validly null if OnStopRequest has already been called. - // We only need the domainLookup timestamps when not loading from cache - if (mDNSPrefetch && mDNSPrefetch->TimingsValid() && mTransaction) { - TimeStamp connectStart = mTransaction->GetConnectStart(); - TimeStamp requestStart = mTransaction->GetRequestStart(); - // We only set the domainLookup timestamps if we're not using a - // persistent connection. - if (requestStart.IsNull() && connectStart.IsNull()) { - mTransaction->SetDomainLookupStart(mDNSPrefetch->StartTimestamp()); - mTransaction->SetDomainLookupEnd(mDNSPrefetch->EndTimestamp()); + if (!httpSSVCRecord) { + // Unset DNS cache refresh if it was requested, + if (mCaps & NS_HTTP_REFRESH_DNS) { + mCaps &= ~NS_HTTP_REFRESH_DNS; + if (mTransaction) { + mTransaction->SetDNSWasRefreshed(); + } } - } - mDNSPrefetch = nullptr; - // Unset DNS cache refresh if it was requested, - if (mCaps & NS_HTTP_REFRESH_DNS) { - mCaps &= ~NS_HTTP_REFRESH_DNS; - if (mTransaction) { - mTransaction->SetDNSWasRefreshed(); + if (!mDNSBlockingPromise.IsEmpty()) { + if (NS_SUCCEEDED(status)) { + nsCOMPtr record(rec); + mDNSBlockingPromise.Resolve(record, __func__); + } else { + mDNSBlockingPromise.Reject(status, __func__); + } } + + return NS_OK; } - if (!mDNSBlockingPromise.IsEmpty()) { - if (NS_SUCCEEDED(status)) { - nsCOMPtr record(rec); - mDNSBlockingPromise.Resolve(record, __func__); - } else { - mDNSBlockingPromise.Reject(status, __func__); - } - } - - return NS_OK; -} - -void nsHttpChannel::OnHTTPSRRAvailable(nsIDNSHTTPSSVCRecord* aRecord) { - MOZ_ASSERT(NS_IsMainThread(), "Expecting DNS callback on main thread."); - - LOG(("nsHttpChannel::OnHTTPSRRAvailable [this=%p, aRecord=%p]\n", this, - aRecord)); - // This record will be used in the new redirect channel. - MOZ_ASSERT(!mHTTPSSVCRecord); - mHTTPSSVCRecord = aRecord; - if (LoadWaitHTTPSSVCRecord()) { MOZ_ASSERT(mURI->SchemeIs("http")); + MOZ_ASSERT(!mHTTPSSVCRecord); - StoreWaitHTTPSSVCRecord(false); - nsresult rv = ContinueOnBeforeConnect(!!mHTTPSSVCRecord, mStatus); + // This record will be used in the new redirect channel. + mHTTPSSVCRecord = httpSSVCRecord; + nsresult rv = ContinueOnBeforeConnect(true, status); if (NS_FAILED(rv)) { CloseCacheEntry(false); Unused << AsyncAbort(rv); } } else { // This channel is not canceled and the transaction is not created. - if (mHTTPSSVCRecord && NS_SUCCEEDED(mStatus) && !mTransaction && + if (NS_SUCCEEDED(mStatus) && !mTransaction && (mFirstResponseSource != RESPONSE_FROM_CACHE)) { bool hasIPAddress = false; - Unused << mHTTPSSVCRecord->GetHasIPAddresses(&hasIPAddress); + Unused << httpSSVCRecord->GetHasIPAddresses(&hasIPAddress); Telemetry::Accumulate(Telemetry::DNS_HTTPSSVC_RECORD_RECEIVING_STAGE, hasIPAddress ? HTTPSSVC_WITH_IPHINT_RECEIVED_STAGE_0 @@ -9114,6 +9060,8 @@ void nsHttpChannel::OnHTTPSRRAvailable(nsIDNSHTTPSSVCRecord* aRecord) { StoreHTTPSSVCTelemetryReported(true); } } + + return NS_OK; } //----------------------------------------------------------------------------- diff --git a/netwerk/protocol/http/nsHttpChannel.h b/netwerk/protocol/http/nsHttpChannel.h index add6331f2d51..8c6cdafed622 100644 --- a/netwerk/protocol/http/nsHttpChannel.h +++ b/netwerk/protocol/http/nsHttpChannel.h @@ -334,8 +334,6 @@ class nsHttpChannel final : public HttpBaseChannel, [[nodiscard]] nsresult OnBeforeConnect(); [[nodiscard]] nsresult ContinueOnBeforeConnect(bool aShouldUpgrade, nsresult aStatus); - nsresult MaybeUseHTTPSRRForUpgrade(bool aShouldUpgrade, nsresult aStatus); - void OnHTTPSRRAvailable(nsIDNSHTTPSSVCRecord* aRecord); void OnBeforeConnectContinue(); [[nodiscard]] nsresult Connect(); void SpeculativeConnect(); diff --git a/netwerk/test/unit/test_httpssvc_https_upgrade.js b/netwerk/test/unit/test_httpssvc_https_upgrade.js deleted file mode 100644 index 47d3290bfd27..000000000000 --- a/netwerk/test/unit/test_httpssvc_https_upgrade.js +++ /dev/null @@ -1,231 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -ChromeUtils.import("resource://gre/modules/NetUtil.jsm"); - -let prefs; -let h2Port; -let listen; - -const dns = Cc["@mozilla.org/network/dns-service;1"].getService( - Ci.nsIDNSService -); -const certOverrideService = Cc[ - "@mozilla.org/security/certoverride;1" -].getService(Ci.nsICertOverrideService); -const threadManager = Cc["@mozilla.org/thread-manager;1"].getService( - Ci.nsIThreadManager -); -const mainThread = threadManager.currentThread; - -const defaultOriginAttributes = {}; - -function setup() { - let env = Cc["@mozilla.org/process/environment;1"].getService( - Ci.nsIEnvironment - ); - h2Port = env.get("MOZHTTP2_PORT"); - Assert.notEqual(h2Port, null); - Assert.notEqual(h2Port, ""); - - // Set to allow the cert presented by our H2 server - do_get_profile(); - prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch); - - prefs.setBoolPref("network.http.spdy.enabled", true); - prefs.setBoolPref("network.http.spdy.enabled.http2", true); - // the TRR server is on 127.0.0.1 - prefs.setCharPref("network.trr.bootstrapAddress", "127.0.0.1"); - - // make all native resolve calls "secretly" resolve localhost instead - prefs.setBoolPref("network.dns.native-is-localhost", true); - - // 0 - off, 1 - race, 2 TRR first, 3 TRR only, 4 shadow - prefs.setIntPref("network.trr.mode", 2); // TRR first - prefs.setBoolPref("network.trr.wait-for-portal", false); - // don't confirm that TRR is working, just go! - prefs.setCharPref("network.trr.confirmationNS", "skip"); - - // So we can change the pref without clearing the cache to check a pushed - // record with a TRR path that fails. - Services.prefs.setBoolPref("network.trr.clear-cache-on-pref-change", false); - - Services.prefs.setBoolPref("network.dns.upgrade_with_https_rr", true); - Services.prefs.setBoolPref("network.dns.use_https_rr_as_altsvc", true); - - Services.prefs.setCharPref( - "network.trr.uri", - "https://foo.example.com:" + h2Port + "/httpssvc_as_altsvc" - ); - - // The moz-http2 cert is for foo.example.com and is signed by http2-ca.pem - // so add that cert to the trust list as a signing cert. // the foo.example.com domain name. - const certdb = Cc["@mozilla.org/security/x509certdb;1"].getService( - Ci.nsIX509CertDB - ); - addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u"); -} - -setup(); -registerCleanupFunction(() => { - prefs.clearUserPref("network.http.spdy.enabled"); - prefs.clearUserPref("network.http.spdy.enabled.http2"); - prefs.clearUserPref("network.dns.localDomains"); - prefs.clearUserPref("network.dns.native-is-localhost"); - prefs.clearUserPref("network.trr.mode"); - prefs.clearUserPref("network.trr.uri"); - prefs.clearUserPref("network.trr.credentials"); - prefs.clearUserPref("network.trr.wait-for-portal"); - prefs.clearUserPref("network.trr.allow-rfc1918"); - prefs.clearUserPref("network.trr.useGET"); - prefs.clearUserPref("network.trr.confirmationNS"); - prefs.clearUserPref("network.trr.bootstrapAddress"); - prefs.clearUserPref("network.trr.request-timeout"); - prefs.clearUserPref("network.trr.clear-cache-on-pref-change"); - prefs.clearUserPref("network.dns.upgrade_with_https_rr"); - prefs.clearUserPref("network.dns.use_https_rr_as_altsvc"); -}); - -class DNSListener { - constructor() { - this.promise = new Promise(resolve => { - this.resolve = resolve; - }); - } - onLookupComplete(inRequest, inRecord, inStatus) { - this.resolve([inRequest, inRecord, inStatus]); - } - // So we can await this as a promise. - then() { - return this.promise.then.apply(this.promise, arguments); - } -} - -DNSListener.prototype.QueryInterface = ChromeUtils.generateQI([ - "nsIDNSListener", -]); - -function makeChan(url) { - let chan = NetUtil.newChannel({ - uri: url, - loadUsingSystemPrincipal: true, - }).QueryInterface(Ci.nsIHttpChannel); - return chan; -} - -function channelOpenPromise(chan, flags) { - return new Promise(resolve => { - function finish(req, buffer) { - certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData( - false - ); - resolve([req, buffer]); - } - certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData( - true - ); - chan.asyncOpen(new ChannelListener(finish, null, flags)); - }); -} - -class EventSinkListener { - getInterface(iid) { - if (iid.equals(Ci.nsIChannelEventSink)) { - return this; - } - } - asyncOnChannelRedirect(oldChan, newChan, flags, callback) { - Assert.equal(oldChan.URI.hostPort, newChan.URI.hostPort); - Assert.equal(oldChan.URI.scheme, "http"); - Assert.equal(newChan.URI.scheme, "https"); - callback.onRedirectVerifyCallback(Cr.NS_OK); - } -} - -EventSinkListener.prototype.QueryInterface = ChromeUtils.generateQI([ - "nsIInterfaceRequestor", - "nsIChannelEventSink", -]); - -// Test if the request is upgraded to https with a HTTPSSVC record. -add_task(async function testUseHTTPSSVCAsHSTS() { - dns.clearCache(true); - - let dnsListener = new DNSListener(); - - // Do DNS resolution before creating the channel, so the HTTPSSVC record will - // be resolved from the cache. - let request = dns.asyncResolve( - "test.httpssvc.com", - dns.RESOLVE_TYPE_HTTPSSVC, - 0, - null, // resolverInfo - dnsListener, - mainThread, - defaultOriginAttributes - ); - - let [inRequest, inRecord, inStatus] = await dnsListener; - Assert.equal(inRequest, request, "correct request was used"); - Assert.equal(inStatus, Cr.NS_OK, "status OK"); - - // Since the HTTPS RR should be served from cache, the DNS record is available - // before nsHttpChannel::MaybeUseHTTPSRRForUpgrade() is called. - let chan = makeChan(`http://test.httpssvc.com:80/server-timing`); - let listener = new EventSinkListener(); - chan.notificationCallbacks = listener; - - let [req, resp] = await channelOpenPromise(chan); - - req.QueryInterface(Ci.nsIHttpChannel); - Assert.equal(req.getResponseHeader("x-connection-http2"), "yes"); - - chan = makeChan(`http://test.httpssvc.com:80/server-timing`); - listener = new EventSinkListener(); - chan.notificationCallbacks = listener; - - [req, resp] = await channelOpenPromise(chan); - - req.QueryInterface(Ci.nsIHttpChannel); - Assert.equal(req.getResponseHeader("x-connection-http2"), "yes"); -}); - -// Test the case that we got an invalid DNS response. -add_task(async function testInvalidDNSResult() { - let dnsListener = new DNSListener(); - - // Do DNS resolution before creating the channel, so the HTTPSSVC record will - // be resolved from the cache. - let request = dns.asyncResolve( - "foo.notexisted.com", - dns.RESOLVE_TYPE_HTTPSSVC, - 0, - null, // resolverInfo - dnsListener, - mainThread, - defaultOriginAttributes - ); - - let [inRequest, inRecord, inStatus] = await dnsListener; - Assert.equal(inRequest, request, "correct request was used"); - Assert.equal(inStatus, Cr.NS_ERROR_UNKNOWN_HOST, "status error"); - - let chan = makeChan(`http://foo.notexisted.com:8888/server-timing`); - let [req, resp] = await channelOpenPromise( - chan, - CL_EXPECT_LATE_FAILURE | CL_ALLOW_UNKNOWN_CL - ); - Assert.equal(req.status, Cr.NS_ERROR_CONNECTION_REFUSED); -}); - -add_task(async function testLiteralIP() { - let chan = makeChan(`http://127.0.0.1:8888/server-timing`); - let [req, resp] = await channelOpenPromise( - chan, - CL_EXPECT_LATE_FAILURE | CL_ALLOW_UNKNOWN_CL - ); - Assert.equal(req.status, Cr.NS_ERROR_CONNECTION_REFUSED); -}); diff --git a/netwerk/test/unit/test_use_httpssvc.js b/netwerk/test/unit/test_use_httpssvc.js index 2e166b12fef9..8288be978c81 100644 --- a/netwerk/test/unit/test_use_httpssvc.js +++ b/netwerk/test/unit/test_use_httpssvc.js @@ -123,88 +123,6 @@ function channelOpenPromise(chan) { }); } -// This is for testing when the HTTPSSVC record is not available when -// the transaction is added in connection manager. -add_task(async function testUseHTTPSSVCForHttpsUpgrade() { - // use the h2 server as DOH provider - prefs.setCharPref( - "network.trr.uri", - "https://foo.example.com:" + h2Port + "/httpssvc_as_altsvc" - ); - dns.clearCache(true); - - certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData( - true - ); - - let chan = makeChan(`https://test.httpssvc.com:8080/`); - let [req, resp] = await channelOpenPromise(chan); - Assert.equal(req.getResponseHeader("x-connection-http2"), "yes"); - - certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData( - false - ); -}); - -class EventSinkListener { - getInterface(iid) { - if (iid.equals(Ci.nsIChannelEventSink)) { - return this; - } - } - asyncOnChannelRedirect(oldChan, newChan, flags, callback) { - Assert.equal(oldChan.URI.hostPort, newChan.URI.hostPort); - Assert.equal(oldChan.URI.scheme, "http"); - Assert.equal(newChan.URI.scheme, "https"); - callback.onRedirectVerifyCallback(Cr.NS_OK); - } -} - -EventSinkListener.prototype.QueryInterface = ChromeUtils.generateQI([ - "nsIInterfaceRequestor", - "nsIChannelEventSink", -]); - -// Test if the request is upgraded to https with a HTTPSSVC record. -add_task(async function testUseHTTPSSVCAsHSTS() { - // use the h2 server as DOH provider - prefs.setCharPref( - "network.trr.uri", - "https://foo.example.com:" + h2Port + "/httpssvc_as_altsvc" - ); - dns.clearCache(true); - - certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData( - true - ); - - // At this time, the DataStorage is not ready, so MaybeUseHTTPSRRForUpgrade() - // is called from the callback of NS_ShouldSecureUpgrade(). - let chan = makeChan(`http://test.httpssvc.com:80/`); - let listener = new EventSinkListener(); - chan.notificationCallbacks = listener; - - let [req, resp] = await channelOpenPromise(chan); - - req.QueryInterface(Ci.nsIHttpChannel); - Assert.equal(req.getResponseHeader("x-connection-http2"), "yes"); - - // At this time, the DataStorage is ready, so MaybeUseHTTPSRRForUpgrade() - // is called from nsHttpChannel::OnBeforeConnect(). - chan = makeChan(`http://test.httpssvc.com:80/`); - listener = new EventSinkListener(); - chan.notificationCallbacks = listener; - - [req, resp] = await channelOpenPromise(chan); - - req.QueryInterface(Ci.nsIHttpChannel); - Assert.equal(req.getResponseHeader("x-connection-http2"), "yes"); - - certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData( - false - ); -}); - // This is for testing when the HTTPSSVC record is already available before // the transaction is added in connection manager. add_task(async function testUseHTTPSSVC() { @@ -248,6 +166,65 @@ add_task(async function testUseHTTPSSVC() { ); }); +// This is for testing when the HTTPSSVC record is not available when +// the transaction is added in connection manager. +add_task(async function testUseHTTPSSVC1() { + dns.clearCache(true); + + certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData( + true + ); + + let chan = makeChan(`https://test.httpssvc.com:8080/`); + let [req, resp] = await channelOpenPromise(chan); + Assert.equal(req.getResponseHeader("x-connection-http2"), "yes"); + + certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData( + false + ); +}); + +class EventSinkListener { + getInterface(iid) { + if (iid.equals(Ci.nsIChannelEventSink)) { + return this; + } + } + asyncOnChannelRedirect(oldChan, newChan, flags, callback) { + Assert.equal(oldChan.URI.hostPort, newChan.URI.hostPort); + Assert.equal(oldChan.URI.scheme, "http"); + Assert.equal(newChan.URI.scheme, "https"); + callback.onRedirectVerifyCallback(Cr.NS_OK); + } +} + +EventSinkListener.prototype.QueryInterface = ChromeUtils.generateQI([ + "nsIInterfaceRequestor", + "nsIChannelEventSink", +]); + +// Test if the request is upgraded to https with a HTTPSSVC record. +add_task(async function testUseHTTPSSVCAsHSTS() { + dns.clearCache(true); + + certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData( + true + ); + + let chan = makeChan(`http://test.httpssvc.com:80/`); + let listener = new EventSinkListener(); + chan.notificationCallbacks = listener; + + let [req, resp] = await channelOpenPromise(chan); + + req.QueryInterface(Ci.nsIHttpChannel); + Assert.equal(req.getResponseHeader("x-connection-http2"), "yes"); + + certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData( + false + ); +}); + // Test if we can successfully fallback to the original host and port. add_task(async function testFallback() { let trrServer = new TRRServer(); diff --git a/netwerk/test/unit/xpcshell.ini b/netwerk/test/unit/xpcshell.ini index c7f7a2f8bd02..dc82415187c3 100644 --- a/netwerk/test/unit/xpcshell.ini +++ b/netwerk/test/unit/xpcshell.ini @@ -511,4 +511,3 @@ run-sequentially = node server exceptions dont replay well [test_httpssvc_retry_without_ech.js] skip-if = asan || tsan || os == 'win' || os =='android' run-sequentially = node server exceptions dont replay well -[test_httpssvc_https_upgrade.js] diff --git a/testing/xpcshell/moz-http2/moz-http2.js b/testing/xpcshell/moz-http2/moz-http2.js index be1340578326..506f8f8612e5 100644 --- a/testing/xpcshell/moz-http2/moz-http2.js +++ b/testing/xpcshell/moz-http2/moz-http2.js @@ -912,12 +912,6 @@ function handleRequest(req, res) { let packet = dnsPacket.decode(payload); let answers = []; if (packet.questions[0].type == "HTTPS") { - let priority = 1; - // Set an invalid priority to test the case when receiving a corrupted - // response. - if (packet.questions[0].name === "foo.notexisted.com") { - priority = 0; - } answers.push({ name: packet.questions[0].name, type: packet.questions[0].type, @@ -925,7 +919,7 @@ function handleRequest(req, res) { class: "IN", flush: false, data: { - priority, + priority: 1, name: "foo.example.com", values: [ { key: "alpn", value: "h2" },