blob: 9d560d58355b145b69052c1546c8509c02054e1c [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 NET_NETWORK_ERROR_LOGGING_NETWORK_ERROR_LOGGING_SERVICE_H_
#define NET_NETWORK_ERROR_LOGGING_NETWORK_ERROR_LOGGING_SERVICE_H_
#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>
#include "base/feature_list.h"
#include "base/macros.h"
#include "base/time/clock.h"
#include "base/time/time.h"
#include "net/base/ip_address.h"
#include "net/base/net_errors.h"
#include "net/base/net_export.h"
#include "net/base/network_isolation_key.h"
#include "url/gurl.h"
#include "url/origin.h"
namespace base {
class Value;
} // namespace base
namespace net {
class ReportingService;
} // namespace net
namespace url {
class Origin;
} // namespace url
namespace features {
extern const base::Feature NET_EXPORT kNetworkErrorLogging;
} // namespace features
namespace net {
class NET_EXPORT NetworkErrorLoggingService {
public:
class PersistentNelStore;
// Every (NIK, origin) pair can have at most one policy.
struct NET_EXPORT NelPolicyKey {
NelPolicyKey();
NelPolicyKey(const NetworkIsolationKey& network_isolation_key,
const url::Origin& origin);
NelPolicyKey(const NelPolicyKey& other);
~NelPolicyKey();
bool operator<(const NelPolicyKey& other) const;
bool operator==(const NelPolicyKey& other) const;
bool operator!=(const NelPolicyKey& other) const;
// The NIK of the request this policy was received from. This will be used
// for any requests uploading reports according to this policy. (Not
// included in the report itself.)
NetworkIsolationKey network_isolation_key;
url::Origin origin;
};
// Used for wildcard policies that are applicable to |domain| and its
// subdomains.
struct WildcardNelPolicyKey {
WildcardNelPolicyKey();
WildcardNelPolicyKey(const NetworkIsolationKey& network_isolation_key,
const std::string& domain);
explicit WildcardNelPolicyKey(const NelPolicyKey& origin_key);
WildcardNelPolicyKey(const WildcardNelPolicyKey& other);
~WildcardNelPolicyKey();
bool operator<(const WildcardNelPolicyKey& other) const;
// The NIK of the request this policy was received from. This will be used
// for any requests uploading reports according to this policy. (Not
// included in the report itself.)
NetworkIsolationKey network_isolation_key;
std::string domain;
};
// NEL policy set by an origin.
struct NET_EXPORT NelPolicy {
NelPolicy();
NelPolicy(const NelPolicy& other);
~NelPolicy();
NelPolicyKey key;
IPAddress received_ip_address = IPAddress();
// Reporting API endpoint group to which reports should be sent.
std::string report_to;
base::Time expires;
double success_fraction = 0.0;
double failure_fraction = 1.0;
bool include_subdomains = false;
// Last time the policy was accessed to create a report, even if no report
// ends up being queued. Also updated when the policy is first set.
mutable base::Time last_used;
};
// The details of a network error that are included in an NEL report.
//
// See http://wicg.github.io/network-error-logging/#dfn-network-error-object
// for details on the semantics of each field.
struct NET_EXPORT RequestDetails {
RequestDetails();
RequestDetails(const RequestDetails& other);
~RequestDetails();
// NetworkIsolationKey of the request triggering the error. Not included
// in the uploaded report.
NetworkIsolationKey network_isolation_key;
GURL uri;
GURL referrer;
std::string user_agent;
IPAddress server_ip;
std::string protocol;
std::string method;
int status_code;
base::TimeDelta elapsed_time;
Error type;
// Upload nesting depth of this request.
//
// If the request is not a Reporting upload, the depth is 0.
//
// If the request is a Reporting upload, the depth is the max of the depth
// of the requests reported within it plus 1. (Non-NEL reports are
// considered to have depth 0.)
int reporting_upload_depth;
};
// The details of a signed exchange report.
struct NET_EXPORT SignedExchangeReportDetails {
SignedExchangeReportDetails();
SignedExchangeReportDetails(const SignedExchangeReportDetails& other);
~SignedExchangeReportDetails();
// NetworkIsolationKey of the request triggering the error. Not included
// in the uploaded report.
NetworkIsolationKey network_isolation_key;
bool success;
std::string type;
GURL outer_url;
GURL inner_url;
GURL cert_url;
std::string referrer;
IPAddress server_ip_address;
std::string protocol;
std::string method;
int32_t status_code;
base::TimeDelta elapsed_time;
std::string user_agent;
};
static const char kHeaderName[];
static const char kReportType[];
static const int kMaxNestedReportDepth;
// Keys for data included in report bodies. Exposed for tests.
static const char kReferrerKey[];
static const char kSamplingFractionKey[];
static const char kServerIpKey[];
static const char kProtocolKey[];
static const char kMethodKey[];
static const char kStatusCodeKey[];
static const char kElapsedTimeKey[];
static const char kPhaseKey[];
static const char kTypeKey[];
static const char kSignedExchangePhaseValue[];
static const char kSignedExchangeBodyKey[];
static const char kOuterUrlKey[];
static const char kInnerUrlKey[];
static const char kCertUrlKey[];
// Maximum number of NEL policies to store before evicting.
static const size_t kMaxPolicies;
static const char kSignedExchangeRequestOutcomeHistogram[];
// Used for histogramming Signed Exchange request outcomes only. Previously,
// the outcome of all requests would be histogrammed, but this was removed in
// crbug.com/1007122 because the histogram was very large and not very useful.
enum class RequestOutcome {
kDiscardedNoNetworkErrorLoggingService = 0,
kDiscardedNoReportingService = 1,
kDiscardedInsecureOrigin = 2,
kDiscardedNoOriginPolicy = 3,
kDiscardedUnmappedError = 4,
kDiscardedReportingUpload = 5,
kDiscardedUnsampledSuccess = 6,
kDiscardedUnsampledFailure = 7,
kQueued = 8,
kDiscardedNonDNSSubdomainReport = 9,
kDiscardedIPAddressMismatch = 10,
kMaxValue = kDiscardedIPAddressMismatch
};
// NEL policies are persisted to disk if |store| is not null.
// The store, if given, should outlive |*this|.
static std::unique_ptr<NetworkErrorLoggingService> Create(
PersistentNelStore* store);
virtual ~NetworkErrorLoggingService();
// Ingests a "NEL:" header received for |network_isolation_key| and |origin|
// from |received_ip_address| with normalized value |value|. May or may not
// actually set a policy for that origin.
virtual void OnHeader(const NetworkIsolationKey& network_isolation_key,
const url::Origin& origin,
const IPAddress& received_ip_address,
const std::string& value) = 0;
// Considers queueing a network error report for the request described in
// |details|. The contents of |details| might be changed, depending on the
// NEL policy associated with the request's origin. Note that |details| is
// passed by value, so that it doesn't need to be copied in this function if
// it needs to be changed. Consider using std::move to pass this parameter if
// the caller doesn't need to access it after this method call.
//
// Note that Network Error Logging can report a fraction of successful
// requests as well (to calculate error rates), so this should be called on
// *all* secure requests. NEL is only available to secure origins, so this is
// not called on any insecure requests.
virtual void OnRequest(RequestDetails details) = 0;
// Queues a Signed Exchange report.
virtual void QueueSignedExchangeReport(
SignedExchangeReportDetails details) = 0;
// Removes browsing data (origin policies) associated with any origin for
// which |origin_filter| returns true.
virtual void RemoveBrowsingData(
const base::RepeatingCallback<bool(const GURL&)>& origin_filter) = 0;
// Removes browsing data (origin policies) for all origins. Allows slight
// optimization over passing an always-true filter to RemoveBrowsingData.
virtual void RemoveAllBrowsingData() = 0;
// Sets the ReportingService that will be used to queue network error reports.
// If |nullptr| is passed, reports will be queued locally or discarded.
// |reporting_service| must outlive the NetworkErrorLoggingService.
// Should not be called again if previously called with a non-null pointer.
void SetReportingService(ReportingService* reporting_service);
// Shuts down the NEL service, so that no more requests or headers can be
// processed, no more reports are queued, and browsing data can no longer be
// cleared.
void OnShutdown();
// Sets a base::Clock (used to track policy expiration) for tests.
// |clock| must outlive the NetworkErrorLoggingService, and cannot be
// nullptr.
void SetClockForTesting(const base::Clock* clock);
// Dumps info about all the currently stored policies, including expired ones.
// Used to display information about NEL policies on the NetLog Reporting tab.
virtual base::Value StatusAsValue() const;
// Gets the (NIK, origin) keys of all currently stored policies, including
// expired ones.
virtual std::set<NelPolicyKey> GetPolicyKeysForTesting();
virtual PersistentNelStore* GetPersistentNelStoreForTesting();
virtual ReportingService* GetReportingServiceForTesting();
protected:
NetworkErrorLoggingService();
// Unowned:
const base::Clock* clock_;
ReportingService* reporting_service_;
bool shut_down_;
private:
DISALLOW_COPY_AND_ASSIGN(NetworkErrorLoggingService);
};
// Persistent storage for NEL policies.
class NET_EXPORT NetworkErrorLoggingService::PersistentNelStore {
public:
using NelPoliciesLoadedCallback =
base::OnceCallback<void(std::vector<NelPolicy>)>;
PersistentNelStore() = default;
virtual ~PersistentNelStore() = default;
// Initializes the store and retrieves stored NEL policies. This will be
// called only once at startup.
virtual void LoadNelPolicies(NelPoliciesLoadedCallback loaded_callback) = 0;
// Adds a NEL policy to the store.
virtual void AddNelPolicy(const NelPolicy& policy) = 0;
// Updates the access time of the NEL policy in the store.
virtual void UpdateNelPolicyAccessTime(const NelPolicy& policy) = 0;
// Deletes a NEL policy from the store.
virtual void DeleteNelPolicy(const NelPolicy& policy) = 0;
// Flushes the store.
virtual void Flush() = 0;
private:
DISALLOW_COPY_AND_ASSIGN(PersistentNelStore);
};
} // namespace net
#endif // NET_NETWORK_ERROR_LOGGING_NETWORK_ERROR_LOGGING_SERVICE_H_