blob: 4a54025588ea40a66e37e2b3623799338c7ec9e2 [file] [log] [blame]
// 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 "net/base/completion_callback.h"
#include "net/dns/host_resolver.h"
#include "net/http/http_request_info.h"
#include "net/url_request/url_request_context_getter.h"
#include "url/gurl.h"
namespace predictors {
struct PreconnectRequest;
struct PreconnectedRequestStats {
PreconnectedRequestStats(const GURL& origin,
bool was_preresolve_cached,
bool was_preconnected);
PreconnectedRequestStats(const PreconnectedRequestStats& other);
~PreconnectedRequestStats();
GURL origin;
bool was_preresolve_cached;
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; }
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<net::HostResolver::Request> request;
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 except the constructor must be called on the IO
// thread. The constructor 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;
};
static const size_t kMaxInflightPreresolves = 3;
PreconnectManager(base::WeakPtr<Delegate> delegate,
scoped_refptr<net::URLRequestContextGetter> context_getter);
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);
// Public for mocking in unit tests. Don't use, internal only.
virtual void PreconnectUrl(const GURL& url,
const GURL& site_for_cookies,
int num_sockets,
bool allow_credentials) const;
virtual std::pair<int, std::unique_ptr<net::HostResolver::Request>>
PreresolveUrl(const GURL& url, const net::CompletionCallback& callback) const;
private:
using PreresolveJobMap = base::IDMap<std::unique_ptr<PreresolveJob>>;
using PreresolveJobId = PreresolveJobMap::KeyType;
friend class PreconnectManagerTest;
void TryToLaunchPreresolveJobs();
void OnPreresolveFinished(PreresolveJobId job_id, int result);
void FinishPreresolve(PreresolveJobId job_id, bool found, bool cached);
void AllPreresolvesForUrlFinished(PreresolveInfo* info);
GURL GetHSTSRedirect(const GURL& url) const;
bool WouldLikelyProxyURL(const GURL& url) const;
base::WeakPtr<Delegate> delegate_;
scoped_refptr<net::URLRequestContextGetter> context_getter_;
std::list<PreresolveJobId> queued_jobs_;
PreresolveJobMap preresolve_jobs_;
std::map<std::string, std::unique_ptr<PreresolveInfo>> preresolve_info_;
size_t inflight_preresolves_count_ = 0;
base::WeakPtrFactory<PreconnectManager> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(PreconnectManager);
};
} // namespace predictors
#endif // CHROME_BROWSER_PREDICTORS_PRECONNECT_MANAGER_H_