blob: 2aceb742c98f2eb89da10b62197956a8deefd9c4 [file] [log] [blame]
// Copyright 2015 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 NET_URL_REQUEST_URL_REQUEST_BACKOFF_MANAGER_H_
#define NET_URL_REQUEST_URL_REQUEST_BACKOFF_MANAGER_H_
#include <stdint.h>
#include <map>
#include <string>
#include "base/macros.h"
#include "base/threading/non_thread_safe.h"
#include "base/time/time.h"
#include "net/base/net_export.h"
#include "net/base/network_change_notifier.h"
#include "url/gurl.h"
namespace net {
class HttpResponseHeaders;
// Class that manages information on Backoff headers. URL requests for HTTPS
// contents should update their URLs in this manager on each response.
//
// Design doc:
// https://docs.google.com/document/d/1aAxwXK7Vw3VigFd6MmrItbAIgMdKAf-XxXXbhWXdID0/edit?usp=sharing
//
// URLRequestBackoffManager maintains a map of URL IDs to
// URLRequestBackoffManager::Entry. It creates an entry when a request receives
// a Backoff header, and does garbage collection from time to time in order to
// clean out outdated entries. URL ID consists of lowercased scheme, host, port
// and path. A newer request with the same ID will override the old entry.
//
// Note that the class does not implement logic to retry a request at random
// with uniform distribution.
// TODO(xunjieli): Expose release time so that the caller can retry accordingly.
class NET_EXPORT URLRequestBackoffManager
: NON_EXPORTED_BASE(public base::NonThreadSafe),
public NetworkChangeNotifier::IPAddressObserver,
public NetworkChangeNotifier::ConnectionTypeObserver {
public:
// Minimum number of seconds that a Backoff header can specify.
static const uint16_t kMinimumBackoffInSeconds;
// Maximum number of seconds that a Backoff header can specify.
static const uint16_t kMaximumBackoffInSeconds;
// Number of throttled requests that will be made between garbage collection.
static const uint16_t kNewEntriesBetweenCollecting;
URLRequestBackoffManager();
~URLRequestBackoffManager() override;
// Updates internal states with a response.
void UpdateWithResponse(const GURL& url,
HttpResponseHeaders* headers,
const base::Time& response_time);
// Returns whether the request should be rejected because of a Backoff header.
bool ShouldRejectRequest(const GURL& url, const base::Time& request_time);
// IPAddressObserver implementation.
void OnIPAddressChanged() override;
// ConnectionTypeObserver implementation.
void OnConnectionTypeChanged(
NetworkChangeNotifier::ConnectionType type) override;
// Used by tests.
int GetNumberOfEntriesForTests() const;
private:
// An struct that holds relevant information obtained from a Backoff header.
struct Entry {
Entry(const base::Time& time1, const base::Time& time2)
: throttled_time(time1), release_time(time2), used(false) {}
~Entry() {}
// Returns whether this entry is outdated.
bool IsOutDated() { return base::Time::Now() >= release_time; }
// Before this time, requests with the same URL ID should be throttled.
const base::Time throttled_time;
// Only one request with the same URL ID should be allowed in
// [|throttled_time|, |release_time|).
// After this time, all requests with the same URL ID are allowed.
const base::Time release_time;
// Indicates whether a request has been made in
// [|throttled_time|, |release_time|).
bool used;
};
// From each URL, generate an ID composed of the scheme, host, port and path
// that allows unique mapping an entry to it.
typedef std::map<std::string, Entry*> UrlEntryMap;
// Method that ensures the map gets cleaned from time to time. The period at
// which garbage collecting happens is adjustable with the
// kNewEntriesBetweenCollecting constant.
void GarbageCollectEntriesIfNecessary();
// Return true if there is a well-formed Backoff header key-value pair,
// and write the Backoff header value in |result|. Return false if no header
// is found or the value is invalid (i.e. less than kMinimumBackoffInSeconds
// or greater than kMaximumBackoffInSeconds).
bool GetBackoffTime(HttpResponseHeaders* headers,
base::TimeDelta* result) const;
// Method that transforms a URL into an ID that can be used in the map.
// Resulting IDs will be lowercase and consist of the scheme, host, port
// and path (without query string, fragment, etc.).
// If the URL is invalid, the invalid spec will be returned, without any
// transformation.
std::string GetIdFromUrl(const GURL& url) const;
// When switching from online to offline or change IP addresses,
// clear all back-off history. This is a precaution in case the change in
// online state now allows communicating without errors with servers that
// were previously returning Backoff headers.
void OnNetworkChange();
UrlEntryMap url_entries_;
// Keeps track of how many new entries are created since last garbage
// collection.
unsigned int new_entries_since_last_gc_;
// Valid after construction.
GURL::Replacements url_id_replacements_;
DISALLOW_COPY_AND_ASSIGN(URLRequestBackoffManager);
};
} // namespace net
#endif // NET_URL_REQUEST_URL_REQUEST_BACKOFF_MANAGER_H_