☠☠ backed out by fb8518702f1b ☠ ☠ | |
author | Dragana Damjanovic <dd.mozilla@gmail.com> |
Wed, 12 Aug 2020 10:11:43 +0000 | |
changeset 544395 | 475139fa091bce7bc1c65522bf3252527d40ca26 |
parent 544394 | fe8a43ec580c0772ad7e80ca72efdc379a30d351 |
child 544396 | 1c4baf6c4aac62b18df19adf27e578f208a1232d |
push id | 124006 |
push user | ddamjanovic@mozilla.com |
push date | Wed, 12 Aug 2020 10:25:34 +0000 |
treeherder | autoland@475139fa091b [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | JuniorHsu, necko-reviewers |
bugs | 1658362 |
milestone | 81.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -1442,16 +1442,22 @@ pref("network.http.spdy.enable-hpack-dum pref("network.http.http3.enabled", false); // Http3 qpack table size. pref("network.http.http3.default-qpack-table-size", 65536); // 64k // Maximal number of streams that can be blocked on waiting for qpack // instructions. pref("network.http.http3.default-max-stream-blocked", 20); + +// This is only for testing! +// This adds alt-svc mapping and it has a form of <host-name>;<alt-svc-header> +// Example: example1.com;h3-29=":443",example2.com;h3-29=":443" +pref("network.http.http3.alt-svc-mapping-for-testing", ""); + // alt-svc allows separation of transport routing from // the origin host without using a proxy. pref("network.http.altsvc.enabled", true); pref("network.http.altsvc.oe", true); // Turn on 0RTT data for TLS 1.3 pref("security.tls.enable_0rtt_data", true);
--- a/netwerk/protocol/http/AlternateServices.cpp +++ b/netwerk/protocol/http/AlternateServices.cpp @@ -54,17 +54,19 @@ bool AltSvcMapping::AcceptableProxy(nsPr return !proxyInfo || proxyInfo->IsDirect() || proxyInfo->IsSOCKS(); } void AltSvcMapping::ProcessHeader( const nsCString& buf, const nsCString& originScheme, const nsCString& originHost, int32_t originPort, const nsACString& username, const nsACString& topWindowOrigin, bool privateBrowsing, bool isolated, nsIInterfaceRequestor* callbacks, nsProxyInfo* proxyInfo, uint32_t caps, - const OriginAttributes& originAttributes) { + const OriginAttributes& originAttributes, + bool aDontValidate /* = false */) { // aDontValidate is only used for + // testing MOZ_ASSERT(NS_IsMainThread()); LOG(("AltSvcMapping::ProcessHeader: %s\n", buf.get())); if (StaticPrefs::network_http_altsvc_proxy_checks() && !AcceptableProxy(proxyInfo)) { LOG(("AltSvcMapping::ProcessHeader ignoring due to proxy\n")); return; } @@ -173,19 +175,22 @@ void AltSvcMapping::ProcessHeader( originAttributes, isHttp3); if (mapping->TTL() <= 0) { LOG(("Alt Svc invalid map")); mapping = nullptr; // since this isn't a parse error, let's clear any existing mapping // as that would have happened if we had accepted the parameters. gHttpHandler->AltServiceCache()->ClearHostMapping( originHost, originPort, originAttributes, topWindowOrigin); + } else if (!aDontValidate) { + gHttpHandler->UpdateAltServiceMapping( + mapping, proxyInfo, callbacks, caps, originAttributes); } else { - gHttpHandler->UpdateAltServiceMapping(mapping, proxyInfo, callbacks, caps, - originAttributes); + gHttpHandler->UpdateAltServiceMappingWithoutValidation(mapping, proxyInfo, callbacks, + caps, originAttributes); } } if (numEntriesInHeader) { // Ignore headers that were just "alt-svc: clear" Telemetry::Accumulate(Telemetry::HTTP_ALTSVC_ENTRIES_PER_HEADER, numEntriesInHeader); } } @@ -949,16 +954,35 @@ already_AddRefed<AltSvcMapping> AltSvcCa return nullptr; } MOZ_ASSERT(rv->Private() == privateBrowsing); LOG(("AltSvcCache::LookupMapping %p HIT %p\n", this, rv.get())); return rv.forget(); } +// This is only used for testing! +void AltSvcCache::UpdateAltServiceMappingWithoutValidation( + AltSvcMapping* map, nsProxyInfo* pi, nsIInterfaceRequestor* aCallbacks, + uint32_t caps, const OriginAttributes& originAttributes) { + MOZ_ASSERT(NS_IsMainThread()); + if (!mStorage) { + return; + } + RefPtr<AltSvcMapping> existing = + LookupMapping(map->HashKey(), map->Private()); + LOG( + ("AltSvcCache::UpdateAltServiceMappingWithoutValidation %p map %p " + "existing %p %s", + this, map, existing.get(), map->AlternateHost().get())); + if (!existing) { + map->SetValidated(true); + } +} + void AltSvcCache::UpdateAltServiceMapping( AltSvcMapping* map, nsProxyInfo* pi, nsIInterfaceRequestor* aCallbacks, uint32_t caps, const OriginAttributes& originAttributes) { MOZ_ASSERT(NS_IsMainThread()); if (!mStorage) { return; } RefPtr<AltSvcMapping> existing =
--- a/netwerk/protocol/http/AlternateServices.h +++ b/netwerk/protocol/http/AlternateServices.h @@ -55,24 +55,24 @@ class AltSvcMapping { const nsACString& alternateHost, int32_t alternatePort, const nsACString& npnToken, const OriginAttributes& originAttributes, bool aIsHttp3); public: AltSvcMapping(DataStorage* storage, int32_t storageEpoch, const nsCString& serialized); - static void ProcessHeader(const nsCString& buf, const nsCString& originScheme, - const nsCString& originHost, int32_t originPort, - const nsACString& username, - const nsACString& topWindowOrigin, - bool privateBrowsing, bool isolated, - nsIInterfaceRequestor* callbacks, - nsProxyInfo* proxyInfo, uint32_t caps, - const OriginAttributes& originAttributes); + static void ProcessHeader( + const nsCString& buf, const nsCString& originScheme, + const nsCString& originHost, int32_t originPort, + const nsACString& username, const nsACString& topWindowOrigin, + bool privateBrowsing, bool isolated, nsIInterfaceRequestor* callbacks, + nsProxyInfo* proxyInfo, uint32_t caps, + const OriginAttributes& originAttributes, + bool aDontValidate = false); // aDontValidate is only used for testing! // AcceptableProxy() decides whether a particular proxy configuration (pi) is // suitable for use with Alt-Svc. No proxy (including a null pi) is suitable. static bool AcceptableProxy(nsProxyInfo* pi); const nsCString& AlternateHost() const { return mAlternateHost; } const nsCString& OriginHost() const { return mOriginHost; } uint32_t OriginPort() const { return mOriginPort; } @@ -186,16 +186,20 @@ class TransactionObserver final : public class AltSvcCache { public: AltSvcCache() : mStorageEpoch(0) {} virtual ~AltSvcCache() = default; void UpdateAltServiceMapping( AltSvcMapping* map, nsProxyInfo* pi, nsIInterfaceRequestor*, uint32_t caps, const OriginAttributes& originAttributes); // main thread + void UpdateAltServiceMappingWithoutValidation( + AltSvcMapping* map, nsProxyInfo* pi, nsIInterfaceRequestor*, + uint32_t caps, + const OriginAttributes& originAttributes); // main thread already_AddRefed<AltSvcMapping> GetAltServiceMapping( const nsACString& scheme, const nsACString& host, int32_t port, bool pb, bool isolated, const nsACString& topWindowOrigin, const OriginAttributes& originAttributes, bool aHttp3Allowed); void ClearAltServiceMappings(); void ClearHostMapping(const nsACString& host, int32_t port, const OriginAttributes& originAttributes, const nsACString& topWindowOrigin);
--- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -6612,16 +6612,24 @@ nsHttpChannel::AsyncOpen(nsIStreamListen gHttpHandler->OnOpeningRequest(this); } mIsPending = true; mWasOpened = true; mListener = listener; + OriginAttributes originAttributes; + StoragePrincipalHelper::GetOriginAttributesForNetworkState(this, + originAttributes); + + gHttpHandler->MaybeAddAltSvcForTesting(mURI, mUsername, GetTopWindowOrigin(), + mPrivateBrowsing, IsIsolated(), + mCallbacks, originAttributes); + if (nsIOService::UseSocketProcess() && !gIOService->IsSocketProcessLaunchComplete()) { RefPtr<nsHttpChannel> self = this; gIOService->CallOrWaitForSocketProcess( [self]() { self->AsyncOpenFinal(TimeStamp::Now()); }); return NS_OK; }
--- a/netwerk/protocol/http/nsHttpHandler.cpp +++ b/netwerk/protocol/http/nsHttpHandler.cpp @@ -1988,16 +1988,33 @@ void nsHttpHandler::PrefsChanged(const c if (userSetImageAcceptHeader.IsEmpty()) { mImageAcceptHeader.Assign(ImageAcceptHeader()); } else { mImageAcceptHeader.Assign(userSetImageAcceptHeader); } } + if (PREF_CHANGED(HTTP_PREF("http3.alt-svc-mapping-for-testing"))) { + nsAutoCString altSvcMappings; + rv = Preferences::GetCString(HTTP_PREF("http3.alt-svc-mapping-for-testing"), + altSvcMappings); + if (NS_SUCCEEDED(rv)) { + nsCCharSeparatedTokenizer tokenizer(altSvcMappings, ','); + while (tokenizer.hasMoreTokens()) { + nsAutoCString token(tokenizer.nextToken()); + int32_t index = token.Find(";"); + if (index != kNotFound) { + auto* map = new nsCString(Substring(token, index + 1)); + mAltSvcMappingTemptativeMap.Put(Substring(token, 0, index), map); + } + } + } + } + // Enable HTTP response timeout if TCP Keepalives are disabled. mResponseTimeoutEnabled = !mTCPKeepaliveShortLivedEnabled && !mTCPKeepaliveLongLivedEnabled; #undef PREF_CHANGED #undef MULTI_PREF_CHANGED } @@ -2909,9 +2926,42 @@ void nsHttpHandler::SetHttpHandlerInitAr mDeviceModelId = aArgs.mDeviceModelId(); } void nsHttpHandler::SetDeviceModelId(const nsCString& aModelId) { MOZ_ASSERT(XRE_IsSocketProcess()); mDeviceModelId = aModelId; } +void nsHttpHandler::MaybeAddAltSvcForTesting( + nsIURI* aUri, const nsACString& aUsername, + const nsACString& aTopWindowOrigin, bool aPrivateBrowsing, bool aIsolated, + nsIInterfaceRequestor* aCallbacks, + const OriginAttributes& aOriginAttributes) { + if (!IsHttp3Enabled() || mAltSvcMappingTemptativeMap.IsEmpty()) { + return; + } + + bool isHttps = false; + if (NS_FAILED(aUri->SchemeIs("https", &isHttps)) || !isHttps) { + // Only set forr HTTPS. + return; + } + + nsAutoCString originHost; + if (NS_FAILED(aUri->GetAsciiHost(originHost))) { + return; + } + + nsCString* map = mAltSvcMappingTemptativeMap.Get(originHost); + if (map) { + int32_t originPort = 80; + aUri->GetPort(&originPort); + LOG(("nsHttpHandler::MaybeAddAltSvcForTesting for %s map: %s", + originHost.get(), PromiseFlatCString(*map).get())); + AltSvcMapping::ProcessHeader(*map, nsCString("https"), originHost, + originPort, aUsername, aTopWindowOrigin, + aPrivateBrowsing, aIsolated, aCallbacks, + nullptr, 0, aOriginAttributes, true); + } +} + } // namespace mozilla::net
--- a/netwerk/protocol/http/nsHttpHandler.h +++ b/netwerk/protocol/http/nsHttpHandler.h @@ -343,16 +343,24 @@ class nsHttpHandler final : public nsIHt // Alternate Services Maps are main thread only void UpdateAltServiceMapping(AltSvcMapping* map, nsProxyInfo* proxyInfo, nsIInterfaceRequestor* callbacks, uint32_t caps, const OriginAttributes& originAttributes) { mAltSvcCache->UpdateAltServiceMapping(map, proxyInfo, callbacks, caps, originAttributes); } + void UpdateAltServiceMappingWithoutValidation( + AltSvcMapping* map, nsProxyInfo* proxyInfo, + nsIInterfaceRequestor* callbacks, uint32_t caps, + const OriginAttributes& originAttributes) { + mAltSvcCache->UpdateAltServiceMappingWithoutValidation( + map, proxyInfo, callbacks, caps, originAttributes); + } + already_AddRefed<AltSvcMapping> GetAltServiceMapping( const nsACString& scheme, const nsACString& host, int32_t port, bool pb, bool isolated, const nsACString& topWindowOrigin, const OriginAttributes& originAttributes, bool aHttp3Allowed) { return mAltSvcCache->GetAltServiceMapping(scheme, host, port, pb, isolated, topWindowOrigin, originAttributes, aHttp3Allowed); } @@ -483,16 +491,22 @@ class nsHttpHandler final : public nsIHt bool GetThroughCaptivePortal() { return mThroughCaptivePortal; } nsresult CompleteUpgrade(HttpTransactionShell* aTrans, nsIHttpUpgradeListener* aUpgradeListener); nsresult DoShiftReloadConnectionCleanupWithConnInfo( nsHttpConnectionInfo* aCI); + + void MaybeAddAltSvcForTesting(nsIURI* aUri, const nsACString& aUsername, + const nsACString& aTopWindowOrigin, + bool aPrivateBrowsing, bool aIsolated, + nsIInterfaceRequestor* aCallbacks, + const OriginAttributes& aOriginAttributes); private: nsHttpHandler(); virtual ~nsHttpHandler(); [[nodiscard]] nsresult Init(); // @@ -830,16 +844,21 @@ class nsHttpHandler final : public nsIHt private: nsTHashtable<nsCStringHashKey> mBlacklistedSpdyOrigins; bool mThroughCaptivePortal; // The mapping of channel id and the weak pointer of nsHttpChannel. nsDataHashtable<nsUint64HashKey, nsWeakPtr> mIDToHttpChannelMap; + + // This is parsed pref network.http.http3.alt-svc-mapping-for-testing. + // The pref set artificial altSvc-s for origin for testing. + // This maps an origin to an altSvc. + nsClassHashtable<nsCStringHashKey, nsCString> mAltSvcMappingTemptativeMap; }; extern StaticRefPtr<nsHttpHandler> gHttpHandler; //----------------------------------------------------------------------------- // nsHttpsHandler - thin wrapper to distinguish the HTTP handler from the // HTTPS handler (even though they share the same impl). //-----------------------------------------------------------------------------
new file mode 100644 --- /dev/null +++ b/netwerk/test/unit/test_altsvc_pref.js @@ -0,0 +1,140 @@ +"use strict"; + +let h3Port; +let h3Route; +let h3AltSvc; +let prefs; +let httpsOrigin; + +let tests = [ + // The altSvc storage may not be up imediately, therefore run test_no_altsvc_pref + // for a couple times to wait for the storage. + test_no_altsvc_pref, + test_no_altsvc_pref, + test_no_altsvc_pref, + test_altsvc_pref, + testsDone, +]; + +let current_test = 0; + +function run_next_test() { + if (current_test < tests.length) { + dump("starting test number " + current_test + "\n"); + tests[current_test](); + current_test++; + } +} + +function run_test() { + let env = Cc["@mozilla.org/process/environment;1"].getService( + Ci.nsIEnvironment + ); + h3Port = env.get("MOZHTTP3_PORT"); + Assert.notEqual(h3Port, null); + Assert.notEqual(h3Port, ""); + h3AltSvc = ":" + h3Port; + + h3Route = "foo.example.com:" + h3Port; + do_get_profile(); + prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch); + + prefs.setBoolPref("network.http.http3.enabled", true); + prefs.setCharPref("network.dns.localDomains", "foo.example.com"); + prefs.setBoolPref("network.dns.disableIPv6", true); + + // The certificate for the http3server server is for foo.example.com and + // is signed by http2-ca.pem so add that cert to the trust list as a + // signing cert. + let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService( + Ci.nsIX509CertDB + ); + addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u"); + httpsOrigin = "https://foo.example.com/"; + + run_next_test(); +} + +let Http3CheckListener = function() {}; + +Http3CheckListener.prototype = { + expectedRoute: "", + expectedStatus: Cr.NS_OK, + + onStartRequest: function testOnStartRequest(request) { + Assert.ok(request instanceof Ci.nsIHttpChannel); + Assert.equal(request.status, this.expectedStatus); + if (Components.isSuccessCode(this.expectedStatus)) { + Assert.equal(request.responseStatus, 200); + } + }, + + onDataAvailable: function testOnDataAvailable(request, stream, off, cnt) { + read_stream(stream, cnt); + }, + + onStopRequest: function testOnStopRequest(request, status) { + Assert.equal(status, this.expectedStatus); + if (Components.isSuccessCode(this.expectedStatus)) { + Assert.equal(request.responseStatus, 200); + let routed = "NA"; + try { + routed = request.getRequestHeader("Alt-Used"); + } catch (e) {} + dump("routed is " + routed + "\n"); + + Assert.equal(routed, this.expectedRoute); + + let httpVersion = ""; + try { + httpVersion = request.protocolVersion; + } catch (e) {} + Assert.equal(httpVersion, "h3"); + } + + run_next_test(); + do_test_finished(); + }, +}; + +function makeChan(uri) { + let chan = NetUtil.newChannel({ + uri, + loadUsingSystemPrincipal: true, + }).QueryInterface(Ci.nsIHttpChannel); + chan.loadFlags = Ci.nsIChannel.LOAD_INITIAL_DOCUMENT_URI; + return chan; +} + +function test_no_altsvc_pref() { + dump("test_no_altsvc_pref"); + do_test_pending(); + + let chan = makeChan(httpsOrigin + "http3-test"); + let listener = new Http3CheckListener(); + listener.expectedStatus = Cr.NS_ERROR_CONNECTION_REFUSED; + chan.asyncOpen(listener); +} + +function test_altsvc_pref() { + dump("test_altsvc_pref"); + do_test_pending(); + + prefs.setCharPref( + "network.http.http3.alt-svc-mapping-for-testing", + "foo.example.com;h3-27=" + h3AltSvc + ); + + let chan = makeChan(httpsOrigin + "http3-test"); + let listener = new Http3CheckListener(); + listener.expectedRoute = h3Route; + chan.asyncOpen(listener); +} + +function testsDone() { + prefs.clearUserPref("network.http.http3.enabled"); + prefs.clearUserPref("network.dns.localDomains"); + prefs.clearUserPref("network.dns.disableIPv6"); + prefs.clearUserPref("network.http.http3.set-alt-svc-mapping-for-testing"); + dump("testDone\n"); +}
--- a/netwerk/test/unit/xpcshell.ini +++ b/netwerk/test/unit/xpcshell.ini @@ -440,8 +440,9 @@ skip-if = asan || tsan || os == 'win' || skip-if = os == "android" [test_trr_case_sensitivity.js] skip-if = os == "android" [test_trr_proxy.js] [test_trr_cname_chain.js] skip-if = os == "android" [test_http_sfv.js] [test_blob_channelname.js] +[test_altsvc_pref.js]