1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
|
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_PREDICTORS_PRECONNECT_MANAGER_H_
#define CHROME_BROWSER_PREDICTORS_PRECONNECT_MANAGER_H_
#include <list>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "base/containers/id_map.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "chrome/browser/predictors/proxy_lookup_client_impl.h"
#include "chrome/browser/predictors/resolve_host_client_impl.h"
#include "chrome/browser/predictors/resource_prefetch_predictor.h"
#include "content/public/browser/storage_partition_config.h"
#include "net/base/network_anonymization_key.h"
#include "services/network/public/mojom/connection_change_observer_client.mojom.h"
#include "url/gurl.h"
namespace content {
class BrowserContext;
}
namespace network {
namespace mojom {
class NetworkContext;
}
} // namespace network
namespace predictors {
struct PreconnectRequest;
struct PreconnectedRequestStats {
PreconnectedRequestStats(const url::Origin& origin, bool was_preconnected);
PreconnectedRequestStats(const PreconnectedRequestStats& other);
~PreconnectedRequestStats();
url::Origin origin;
bool was_preconnected;
};
struct PreconnectStats {
explicit PreconnectStats(const GURL& url);
// Stats must be moved only.
PreconnectStats(const PreconnectStats&) = delete;
PreconnectStats& operator=(const PreconnectStats&) = delete;
~PreconnectStats();
GURL url;
base::TimeTicks start_time;
std::vector<PreconnectedRequestStats> requests_stats;
};
// Stores the status of all preconnects associated with a given |url|.
struct PreresolveInfo {
PreresolveInfo(const GURL& url, size_t count);
PreresolveInfo(const PreresolveInfo&) = delete;
PreresolveInfo& operator=(const PreresolveInfo&) = delete;
~PreresolveInfo();
bool is_done() const { return queued_count == 0 && inflight_count == 0; }
GURL url;
size_t queued_count;
size_t inflight_count = 0;
bool was_canceled = false;
std::unique_ptr<PreconnectStats> stats;
};
// Stores all data need for running a preresolve and a subsequent optional
// preconnect for a |url|.
struct PreresolveJob {
PreresolveJob(
const GURL& url,
int num_sockets,
bool allow_credentials,
net::NetworkAnonymizationKey network_anonymization_key,
net::NetworkTrafficAnnotationTag traffic_annotation_tag,
std::optional<content::StoragePartitionConfig> storage_partition_config,
std::optional<net::ConnectionKeepAliveConfig> keepalive_config,
mojo::PendingRemote<network::mojom::ConnectionChangeObserverClient>
connection_change_observer_client,
PreresolveInfo* info);
PreresolveJob(const PreresolveJob&) = delete;
PreresolveJob& operator=(const PreresolveJob&) = delete;
PreresolveJob(PreconnectRequest preconnect_request, PreresolveInfo* info);
PreresolveJob(PreresolveJob&& other);
~PreresolveJob();
bool need_preconnect() const {
return num_sockets > 0 && !(info && info->was_canceled);
}
GURL url;
int num_sockets;
bool allow_credentials;
net::NetworkAnonymizationKey network_anonymization_key;
net::NetworkTrafficAnnotationTag traffic_annotation_tag;
// The default for the profile is used if this is absent.
std::optional<content::StoragePartitionConfig> storage_partition_config;
std::optional<net::ConnectionKeepAliveConfig> keepalive_config;
mojo::PendingRemote<network::mojom::ConnectionChangeObserverClient>
connection_change_observer_client;
// Raw pointer usage is fine here because even though PreresolveJob can
// outlive PreresolveInfo. It's only accessed on PreconnectManager class
// context and PreresolveInfo lifetime is tied to PreconnectManager.
// May be equal to nullptr in case of detached job.
raw_ptr<PreresolveInfo, DanglingUntriaged> info;
std::unique_ptr<ResolveHostClientImpl> resolve_host_client;
std::unique_ptr<ProxyLookupClientImpl> proxy_lookup_client;
base::TimeTicks creation_time;
};
// PreconnectManager is responsible for preresolving and preconnecting to
// origins based on the input list of URLs.
// - The input list of URLs is associated with a main frame url that can be
// used for cancelling.
// - Limits the total number of preresolves in flight.
// - Preresolves an URL before preconnecting to it to have a better control on
// number of speculative dns requests in flight.
// - When stopped, waits for the pending preresolve requests to finish without
// issuing preconnects for them.
// - All methods of the class must be called on the UI thread.
class PreconnectManager {
public:
class Delegate {
public:
virtual ~Delegate() = default;
// Called when a preconnect to |preconnect_url| is initiated for |url|.
virtual void PreconnectInitiated(const GURL& url,
const GURL& preconnect_url) = 0;
// Called when all preresolve jobs for the |stats->url| are finished. Note
// that some preconnect jobs can be still in progress, because they are
// fire-and-forget.
// Is called on the UI thread.
virtual void PreconnectFinished(std::unique_ptr<PreconnectStats> stats) = 0;
};
// An observer for testing.
class Observer {
public:
virtual ~Observer() = default;
virtual void OnPreconnectUrl(const GURL& url,
int num_sockets,
bool allow_credentials) {}
virtual void OnPreresolveFinished(
const GURL& url,
const net::NetworkAnonymizationKey& network_anonymization_key,
mojo::PendingRemote<network::mojom::ConnectionChangeObserverClient>&
observer,
bool success) {}
virtual void OnProxyLookupFinished(
const GURL& url,
const net::NetworkAnonymizationKey& network_anonymization_key,
bool success) {}
};
static const size_t kMaxInflightPreresolves = 3;
PreconnectManager(base::WeakPtr<Delegate> delegate,
content::BrowserContext* browser_context);
PreconnectManager(const PreconnectManager&) = delete;
PreconnectManager& operator=(const PreconnectManager&) = delete;
virtual ~PreconnectManager();
// Starts preconnect and preresolve jobs associated with |url|.
virtual void Start(const GURL& url, std::vector<PreconnectRequest> requests);
// Starts special preconnect and preresolve jobs that are not cancellable and
// don't report about their completion. They are considered more important
// than trackable requests thus they are put in the front of the jobs queue.
//
// |network_anonymization_key| specifies the key that the corresponding
// network requests are expected to use. If a request is issued with a
// different key, it may not use the prefetched DNS entry or preconnected
// socket.
virtual void StartPreresolveHost(
const GURL& url,
const net::NetworkAnonymizationKey& network_anonymization_key,
net::NetworkTrafficAnnotationTag traffic_annotation,
const content::StoragePartitionConfig* storage_partition_config);
virtual void StartPreresolveHosts(
const std::vector<GURL>& urls,
const net::NetworkAnonymizationKey& network_anonymization_key,
net::NetworkTrafficAnnotationTag traffic_annotation,
const content::StoragePartitionConfig* storage_partition_config);
virtual void StartPreconnectUrl(
const GURL& url,
bool allow_credentials,
net::NetworkAnonymizationKey network_anonymization_key,
net::NetworkTrafficAnnotationTag traffic_annotation,
const content::StoragePartitionConfig* storage_partition_config,
std::optional<net::ConnectionKeepAliveConfig> keepalive_config,
mojo::PendingRemote<network::mojom::ConnectionChangeObserverClient>
connection_change_observer_client);
// No additional jobs associated with the |url| will be queued after this.
virtual void Stop(const GURL& url);
base::WeakPtr<PreconnectManager> GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
void SetNetworkContextForTesting(
network::mojom::NetworkContext* network_context) {
network_context_ = network_context;
}
void SetObserverForTesting(Observer* observer) { observer_ = observer; }
private:
using PreresolveJobMap = base::IDMap<std::unique_ptr<PreresolveJob>>;
using PreresolveJobId = PreresolveJobMap::KeyType;
friend class PreconnectManagerTest;
void PreconnectUrl(
const GURL& url,
int num_sockets,
bool allow_credentials,
const net::NetworkAnonymizationKey& network_anonymization_key,
const net::NetworkTrafficAnnotationTag& traffic_annotation,
const content::StoragePartitionConfig* storage_partition_config,
std::optional<net::ConnectionKeepAliveConfig> keepalive_config,
mojo::PendingRemote<network::mojom::ConnectionChangeObserverClient>
connection_change_observer_client) const;
std::unique_ptr<ResolveHostClientImpl> PreresolveUrl(
const GURL& url,
const net::NetworkAnonymizationKey& network_anonymization_key,
const content::StoragePartitionConfig* storage_partition_config,
ResolveHostCallback callback) const;
std::unique_ptr<ProxyLookupClientImpl> LookupProxyForUrl(
const GURL& url,
const net::NetworkAnonymizationKey& network_anonymization_key,
const content::StoragePartitionConfig* storage_partition_config,
ProxyLookupCallback callback) const;
// Whether the PreconnectManager should be performing preloading operations
// or if preloading is disabled.
bool IsEnabled();
void TryToLaunchPreresolveJobs();
void OnPreresolveFinished(PreresolveJobId job_id, bool success);
void OnProxyLookupFinished(PreresolveJobId job_id, bool success);
void FinishPreresolveJob(PreresolveJobId job_id, bool success);
void AllPreresolvesForUrlFinished(PreresolveInfo* info);
// NOTE: Returns a non-null pointer outside of unittesting contexts.
network::mojom::NetworkContext* GetNetworkContext(
const content::StoragePartitionConfig* storage_partition_config) const;
base::WeakPtr<Delegate> delegate_;
const raw_ptr<content::BrowserContext> browser_context_;
std::list<PreresolveJobId> queued_jobs_;
PreresolveJobMap preresolve_jobs_;
std::map<GURL, std::unique_ptr<PreresolveInfo>> preresolve_info_;
size_t inflight_preresolves_count_ = 0;
// Only used in tests.
raw_ptr<network::mojom::NetworkContext> network_context_ = nullptr;
raw_ptr<Observer> observer_ = nullptr;
base::WeakPtrFactory<PreconnectManager> weak_factory_{this};
};
} // namespace predictors
#endif // CHROME_BROWSER_PREDICTORS_PRECONNECT_MANAGER_H_
|