| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // 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/ref_counted.h" |
| #include "base/memory/weak_ptr.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 "url/gurl.h" |
| |
| class Profile; |
| |
| namespace network { |
| namespace mojom { |
| class NetworkContext; |
| } |
| } // namespace network |
| |
| namespace predictors { |
| |
| struct PreconnectRequest; |
| |
| struct PreconnectedRequestStats { |
| PreconnectedRequestStats(const GURL& origin, |
| bool was_preconnected); |
| PreconnectedRequestStats(const PreconnectedRequestStats& other); |
| ~PreconnectedRequestStats(); |
| |
| GURL origin; |
| bool was_preconnected; |
| }; |
| |
| struct PreconnectStats { |
| explicit PreconnectStats(const GURL& url); |
| ~PreconnectStats(); |
| |
| GURL url; |
| base::TimeTicks start_time; |
| std::vector<PreconnectedRequestStats> requests_stats; |
| |
| // Stats must be moved only. |
| DISALLOW_COPY_AND_ASSIGN(PreconnectStats); |
| }; |
| |
| // Stores the status of all preconnects associated with a given |url|. |
| struct PreresolveInfo { |
| PreresolveInfo(const GURL& url, size_t count); |
| ~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; |
| |
| DISALLOW_COPY_AND_ASSIGN(PreresolveInfo); |
| }; |
| |
| // 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, |
| 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; |
| // 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. |
| PreresolveInfo* info; |
| std::unique_ptr<ResolveHostClientImpl> resolve_host_client; |
| std::unique_ptr<ProxyLookupClientImpl> proxy_lookup_client; |
| |
| DISALLOW_COPY_AND_ASSIGN(PreresolveJob); |
| }; |
| |
| // 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() {} |
| |
| // 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() {} |
| |
| virtual void OnPreconnectUrl(const GURL& url, |
| int num_sockets, |
| bool allow_credentials) {} |
| |
| virtual void OnPreresolveFinished(const GURL& url, bool success) {} |
| virtual void OnProxyLookupFinished(const GURL& url, bool success) {} |
| }; |
| |
| static const size_t kMaxInflightPreresolves = 3; |
| |
| PreconnectManager(base::WeakPtr<Delegate> delegate, Profile* profile); |
| virtual ~PreconnectManager(); |
| |
| // Starts preconnect and preresolve jobs keyed by |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. |
| virtual void StartPreresolveHost(const GURL& url); |
| virtual void StartPreresolveHosts(const std::vector<std::string>& hostnames); |
| virtual void StartPreconnectUrl(const GURL& url, bool allow_credentials); |
| |
| // No additional jobs keyed by 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; |
| std::unique_ptr<ResolveHostClientImpl> PreresolveUrl( |
| const GURL& url, |
| ResolveHostCallback callback) const; |
| std::unique_ptr<ProxyLookupClientImpl> LookupProxyForUrl( |
| const GURL& url, |
| ProxyLookupCallback callback) const; |
| |
| 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); |
| network::mojom::NetworkContext* GetNetworkContext() const; |
| |
| base::WeakPtr<Delegate> delegate_; |
| Profile* const profile_; |
| std::list<PreresolveJobId> queued_jobs_; |
| PreresolveJobMap preresolve_jobs_; |
| std::map<std::string, std::unique_ptr<PreresolveInfo>> preresolve_info_; |
| size_t inflight_preresolves_count_ = 0; |
| |
| // Only used in tests. |
| network::mojom::NetworkContext* network_context_ = nullptr; |
| Observer* observer_ = nullptr; |
| |
| base::WeakPtrFactory<PreconnectManager> weak_factory_; |
| |
| DISALLOW_COPY_AND_ASSIGN(PreconnectManager); |
| }; |
| |
| } // namespace predictors |
| |
| #endif // CHROME_BROWSER_PREDICTORS_PRECONNECT_MANAGER_H_ |