/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* 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/. */ #include "mozilla/dom/SpeculationRulesManager.h" #include "mozilla/Maybe.h" #include "mozilla/dom/Document.h" #include "mozilla/dom/PrefetchIPCTypes.h" #include "mozilla/dom/PrefetchLog.h" #include "mozilla/dom/PrefetchTypes.h" #include "mozilla/dom/ReferrerInfo.h" #include "mozilla/dom/WindowGlobalChild.h" #include "mozilla/dom/speculationrules_ffi_generated.h" #include "nsNetUtil.h" #include "nsTHashSet.h" namespace mozilla::dom { void SpeculationRulesManager::RemoveRecord(PrefetchRecordChild* aRecord) { mPrefetchRecords.RemoveElement(aRecord); } void SpeculationRulesManager::StartPrefetch(Document* aDocument, const PrefetchCandidate& aCand) { WindowGlobalChild* wgc = aDocument->GetWindowGlobalChild(); if (!wgc || wgc->IsClosed()) { return; } nsCOMPtr uri; if (NS_FAILED(NS_NewURI(getter_AddRefs(uri), aCand.url))) { LOG_SPECRULES_WARN( ("StartPrefetch: invalid candidate URL '%s'", aCand.url.get())); return; } nsCOMPtr referrerInfo = new ReferrerInfo(aDocument->GetDocumentURIAsReferrer(), static_cast(aCand.referrer_policy)); nsString noVarySearchHint; if (!aCand.no_vary_search_hint.IsVoid()) { CopyUTF8toUTF16(aCand.no_vary_search_hint, noVarySearchHint); } nsTArray> tags; for (const nsCString& tag : aCand.tags) { tags.AppendElement(tag.IsVoid() ? Nothing() : Some(NS_ConvertUTF8toUTF16(tag))); } const bool anonymizeClientIP = false; SpeculativePrefetchArgs args(WrapNotNull(uri.get()), referrerInfo, noVarySearchHint, anonymizeClientIP, std::move(tags)); auto actor = MakeRefPtr(uri, PrefetchAnonymizationPolicy::None); if (!wgc->SendPPrefetchRecordConstructor(actor.get(), args)) { LOG_SPECRULES(("StartPrefetch: IPC send failed")); return; } mPrefetchRecords.AppendElement(std::move(actor)); } void SpeculationRulesManager::CancelStalePrefetches( const nsTArray& aStillSpeculated) { nsTHashSet stillSpeculatedUrls; for (const PrefetchCandidate& cand : aStillSpeculated) { stillSpeculatedUrls.Insert(cand.url); } nsTArray> stale; mPrefetchRecords.RemoveElementsBy( [&](const RefPtr& aRecord) { nsAutoCString spec; if (aRecord->URL()) { aRecord->URL()->GetSpec(spec); } if (stillSpeculatedUrls.Contains(spec)) { return false; } stale.AppendElement(aRecord); return true; }); // Cancel and destroy the stale actors only after mPrefetchRecords has been // fully updated above: Send__delete__ synchronously runs ActorDestroy, // which re-enters SpeculationRulesManager::RemoveRecord and mutates // mPrefetchRecords, which RemoveElementsBy above does not tolerate while // it's still iterating. for (const RefPtr& record : stale) { nsAutoCString spec; if (record->URL()) { record->URL()->GetSpec(spec); } LOG_SPECRULES(("CancelStalePrefetches: canceling %s", spec.get())); record->SendCancel(); PrefetchRecordChild::Send__delete__(record); } } } // namespace mozilla::dom