summaryrefslogtreecommitdiff
path: root/chromium/net/network_error_logging
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2018-05-15 10:20:33 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2018-05-15 10:28:57 +0000
commitd17ea114e5ef69ad5d5d7413280a13e6428098aa (patch)
tree2c01a75df69f30d27b1432467cfe7c1467a498da /chromium/net/network_error_logging
parent8c5c43c7b138c9b4b0bf56d946e61d3bbc111bec (diff)
downloadqtwebengine-chromium-d17ea114e5ef69ad5d5d7413280a13e6428098aa.tar.gz
BASELINE: Update Chromium to 67.0.3396.47
Change-Id: Idcb1341782e417561a2473eeecc82642dafda5b7 Reviewed-by: Michal Klocek <michal.klocek@qt.io>
Diffstat (limited to 'chromium/net/network_error_logging')
-rw-r--r--chromium/net/network_error_logging/network_error_logging_end_to_end_test.cc72
-rw-r--r--chromium/net/network_error_logging/network_error_logging_service.cc219
-rw-r--r--chromium/net/network_error_logging/network_error_logging_service.h24
-rw-r--r--chromium/net/network_error_logging/network_error_logging_service_unittest.cc79
4 files changed, 303 insertions, 91 deletions
diff --git a/chromium/net/network_error_logging/network_error_logging_end_to_end_test.cc b/chromium/net/network_error_logging/network_error_logging_end_to_end_test.cc
index c5bc1b75b56..56fadcf5ddf 100644
--- a/chromium/net/network_error_logging/network_error_logging_end_to_end_test.cc
+++ b/chromium/net/network_error_logging/network_error_logging_end_to_end_test.cc
@@ -4,8 +4,10 @@
#include "base/macros.h"
#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/strings/stringprintf.h"
#include "base/test/values_test_util.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "base/values.h"
#include "build/build_config.h"
@@ -52,7 +54,8 @@ class HungHttpResponse : public test_server::HttpResponse {
class NetworkErrorLoggingEndToEndTest : public ::testing::Test {
protected:
NetworkErrorLoggingEndToEndTest()
- : test_server_(test_server::EmbeddedTestServer::TYPE_HTTPS),
+ : main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
+ test_server_(test_server::EmbeddedTestServer::TYPE_HTTPS),
upload_should_hang_(false),
upload_received_(false) {
// Make report delivery happen instantly.
@@ -61,8 +64,8 @@ class NetworkErrorLoggingEndToEndTest : public ::testing::Test {
URLRequestContextBuilder builder;
#if defined(OS_LINUX) || defined(OS_ANDROID)
- builder.set_proxy_config_service(
- std::make_unique<ProxyConfigServiceFixed>(ProxyConfig::CreateDirect()));
+ builder.set_proxy_config_service(std::make_unique<ProxyConfigServiceFixed>(
+ ProxyConfigWithAnnotation::CreateDirect()));
#endif // defined(OS_LINUX) || defined(OS_ANDROID)
builder.set_reporting_policy(std::move(policy));
builder.set_network_error_logging_enabled(true);
@@ -83,6 +86,10 @@ class NetworkErrorLoggingEndToEndTest : public ::testing::Test {
EXPECT_TRUE(test_server_.Start());
}
+ ~NetworkErrorLoggingEndToEndTest() override {
+ EXPECT_TRUE(test_server_.ShutdownAndWaitUntilComplete());
+ }
+
GURL GetConfigureURL() { return test_server_.GetURL(kConfigurePath); }
GURL GetFailURL() { return test_server_.GetURL(kFailPath); }
@@ -123,14 +130,11 @@ class NetworkErrorLoggingEndToEndTest : public ::testing::Test {
if (request.relative_url != kReportPath)
return nullptr;
- EXPECT_FALSE(upload_received_);
- upload_received_ = true;
-
EXPECT_TRUE(request.has_content);
- upload_content_ = request.content;
-
- if (!upload_closure_.is_null())
- std::move(upload_closure_).Run();
+ main_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&NetworkErrorLoggingEndToEndTest::OnUploadReceived,
+ base::Unretained(this), request.content));
if (upload_should_hang_)
return std::make_unique<HungHttpResponse>();
@@ -141,44 +145,51 @@ class NetworkErrorLoggingEndToEndTest : public ::testing::Test {
return std::move(response);
}
+ void OnUploadReceived(std::string content) {
+ upload_received_ = true;
+ upload_content_ = content;
+ upload_run_loop_.Quit();
+ }
+
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
std::unique_ptr<URLRequestContext> url_request_context_;
test_server::EmbeddedTestServer test_server_;
bool upload_should_hang_;
bool upload_received_;
std::string upload_content_;
- base::OnceClosure upload_closure_;
+ base::RunLoop upload_run_loop_;
private:
DISALLOW_COPY_AND_ASSIGN(NetworkErrorLoggingEndToEndTest);
};
-TEST_F(NetworkErrorLoggingEndToEndTest, ReportNetworkError) {
+#if defined(OS_WIN)
+// TODO(https://crbug.com/829650): Fix and re-enable these tests.
+#define MAYBE_ReportNetworkError DISABLED_ReportNetworkError
+#else
+#define MAYBE_ReportNetworkError ReportNetworkError
+#endif
+TEST_F(NetworkErrorLoggingEndToEndTest, MAYBE_ReportNetworkError) {
TestDelegate configure_delegate;
+ configure_delegate.set_quit_on_complete(false);
auto configure_request = url_request_context_->CreateRequest(
GetConfigureURL(), DEFAULT_PRIORITY, &configure_delegate,
TRAFFIC_ANNOTATION_FOR_TESTS);
configure_request->set_method("GET");
configure_request->Start();
- base::RunLoop().Run();
- EXPECT_TRUE(configure_request->status().is_success());
TestDelegate fail_delegate;
+ fail_delegate.set_quit_on_complete(false);
auto fail_request = url_request_context_->CreateRequest(
GetFailURL(), DEFAULT_PRIORITY, &fail_delegate,
TRAFFIC_ANNOTATION_FOR_TESTS);
fail_request->set_method("GET");
fail_request->Start();
- base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::FAILED, fail_request->status().status());
- EXPECT_EQ(ERR_EMPTY_RESPONSE, fail_request->status().error());
-
- if (!upload_received_) {
- base::RunLoop run_loop;
- upload_closure_ = run_loop.QuitClosure();
- run_loop.Run();
- }
+ upload_run_loop_.Run();
+
+ EXPECT_TRUE(upload_received_);
auto reports = base::test::ParseJson(upload_content_);
base::ListValue* reports_list;
@@ -197,27 +208,34 @@ TEST_F(NetworkErrorLoggingEndToEndTest, ReportNetworkError) {
ExpectDictStringValue(GetFailURL().spec(), *body_dict, "uri");
}
+#if defined(OS_WIN)
+// TODO(https://crbug.com/829650): Fix and re-enable these tests.
+#define MAYBE_UploadAtShutdown DISABLED_UploadAtShutdown
+#else
+#define MAYBE_UploadAtShutdown UploadAtShutdown
+#endif
// Make sure an upload that is in progress at shutdown does not crash.
// This verifies that https://crbug.com/792978 is fixed.
-TEST_F(NetworkErrorLoggingEndToEndTest, UploadAtShutdown) {
+TEST_F(NetworkErrorLoggingEndToEndTest, MAYBE_UploadAtShutdown) {
upload_should_hang_ = true;
TestDelegate configure_delegate;
+ configure_delegate.set_quit_on_complete(false);
auto configure_request = url_request_context_->CreateRequest(
GetConfigureURL(), DEFAULT_PRIORITY, &configure_delegate,
TRAFFIC_ANNOTATION_FOR_TESTS);
configure_request->set_method("GET");
configure_request->Start();
- base::RunLoop().Run();
- EXPECT_TRUE(configure_request->status().is_success());
TestDelegate fail_delegate;
+ fail_delegate.set_quit_on_complete(false);
auto fail_request = url_request_context_->CreateRequest(
GetFailURL(), DEFAULT_PRIORITY, &fail_delegate,
TRAFFIC_ANNOTATION_FOR_TESTS);
fail_request->set_method("GET");
fail_request->Start();
- base::RunLoop().RunUntilIdle();
+
+ upload_run_loop_.Run();
// Let Reporting and NEL shut down with the upload still pending to see if
// they crash.
diff --git a/chromium/net/network_error_logging/network_error_logging_service.cc b/chromium/net/network_error_logging/network_error_logging_service.cc
index d8516dcee48..34dbf6e3b20 100644
--- a/chromium/net/network_error_logging/network_error_logging_service.cc
+++ b/chromium/net/network_error_logging/network_error_logging_service.cc
@@ -10,7 +10,7 @@
#include "base/json/json_reader.h"
#include "base/logging.h"
-#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
#include "base/rand_util.h"
#include "base/time/default_tick_clock.h"
#include "base/time/tick_clock.h"
@@ -20,7 +20,6 @@
#include "net/base/net_errors.h"
#include "net/network_error_logging/network_error_logging_delegate.h"
#include "net/reporting/reporting_service.h"
-#include "net/socket/next_proto.h"
#include "url/gurl.h"
#include "url/origin.h"
@@ -28,9 +27,12 @@ namespace net {
namespace {
+const int kMaxJsonSize = 16 * 1024;
+const int kMaxJsonDepth = 4;
+
const char kReportToKey[] = "report-to";
const char kMaxAgeKey[] = "max-age";
-const char kIncludeSubdomainsKey[] = "includeSubdomains";
+const char kIncludeSubdomainsKey[] = "include-subdomains";
const char kSuccessFractionKey[] = "success-fraction";
const char kFailureFractionKey[] = "failure-fraction";
@@ -114,9 +116,52 @@ bool IsHttpError(const NetworkErrorLoggingService::RequestDetails& request) {
return request.status_code >= 400 && request.status_code < 600;
}
-bool RequestWasSuccessful(
- const NetworkErrorLoggingService::RequestDetails& request) {
- return request.type == OK && !IsHttpError(request);
+enum class HeaderOutcome {
+ DISCARDED_NO_NETWORK_ERROR_LOGGING_SERVICE = 0,
+ DISCARDED_INVALID_SSL_INFO = 1,
+ DISCARDED_CERT_STATUS_ERROR = 2,
+
+ DISCARDED_INSECURE_ORIGIN = 3,
+
+ DISCARDED_JSON_TOO_BIG = 4,
+ DISCARDED_JSON_INVALID = 5,
+ DISCARDED_NOT_DICTIONARY = 6,
+ DISCARDED_TTL_MISSING = 7,
+ DISCARDED_TTL_NOT_INTEGER = 8,
+ DISCARDED_TTL_NEGATIVE = 9,
+ DISCARDED_REPORT_TO_MISSING = 10,
+ DISCARDED_REPORT_TO_NOT_STRING = 11,
+
+ REMOVED = 12,
+ SET = 13,
+
+ MAX
+};
+
+void RecordHeaderOutcome(HeaderOutcome outcome) {
+ UMA_HISTOGRAM_ENUMERATION("Net.NetworkErrorLogging.HeaderOutcome", outcome,
+ HeaderOutcome::MAX);
+}
+
+enum class RequestOutcome {
+ DISCARDED_NO_NETWORK_ERROR_LOGGING_SERVICE = 0,
+
+ DISCARDED_NO_REPORTING_SERVICE = 1,
+ DISCARDED_INSECURE_ORIGIN = 2,
+ DISCARDED_NO_ORIGIN_POLICY = 3,
+ DISCARDED_UNMAPPED_ERROR = 4,
+ DISCARDED_REPORTING_UPLOAD = 5,
+ DISCARDED_UNSAMPLED_SUCCESS = 6,
+ DISCARDED_UNSAMPLED_FAILURE = 7,
+
+ QUEUED = 8,
+
+ MAX
+};
+
+void RecordRequestOutcome(RequestOutcome outcome) {
+ UMA_HISTOGRAM_ENUMERATION("Net.NetworkErrorLogging.RequestOutcome", outcome,
+ RequestOutcome::MAX);
}
class NetworkErrorLoggingServiceImpl : public NetworkErrorLoggingService {
@@ -127,18 +172,23 @@ class NetworkErrorLoggingServiceImpl : public NetworkErrorLoggingService {
DCHECK(delegate_);
}
- // NetworkErrorLoggingService implementation:
-
~NetworkErrorLoggingServiceImpl() override = default;
+ // NetworkErrorLoggingService implementation:
+
void OnHeader(const url::Origin& origin, const std::string& value) override {
// NEL is only available to secure origins, so don't permit insecure origins
// to set policies.
- if (!origin.GetURL().SchemeIsCryptographic())
+ if (!origin.GetURL().SchemeIsCryptographic()) {
+ RecordHeaderOutcome(HeaderOutcome::DISCARDED_INSECURE_ORIGIN);
return;
+ }
OriginPolicy policy;
- if (!ParseHeader(value, tick_clock_->NowTicks(), &policy))
+ HeaderOutcome outcome =
+ ParseHeader(value, tick_clock_->NowTicks(), &policy);
+ RecordHeaderOutcome(outcome);
+ if (outcome != HeaderOutcome::SET && outcome != HeaderOutcome::REMOVED)
return;
PolicyMap::iterator it = policies_.find(origin);
@@ -156,43 +206,70 @@ class NetworkErrorLoggingServiceImpl : public NetworkErrorLoggingService {
}
void OnRequest(const RequestDetails& details) override {
- if (!reporting_service_)
- return;
-
- // It is expected for Reporting uploads to terminate with ERR_ABORTED, since
- // the ReportingUploader cancels them after receiving the response code and
- // headers.
- if (details.is_reporting_upload && details.type == ERR_ABORTED)
+ if (!reporting_service_) {
+ RecordRequestOutcome(RequestOutcome::DISCARDED_NO_REPORTING_SERVICE);
return;
+ }
// NEL is only available to secure origins, so ignore network errors from
// insecure origins. (The check in OnHeader prevents insecure origins from
// setting policies, but this check is needed to ensure that insecure
// origins can't match wildcard policies from secure origins.)
- if (!details.uri.SchemeIsCryptographic())
+ if (!details.uri.SchemeIsCryptographic()) {
+ RecordRequestOutcome(RequestOutcome::DISCARDED_INSECURE_ORIGIN);
return;
+ }
const OriginPolicy* policy =
FindPolicyForOrigin(url::Origin::Create(details.uri));
- if (!policy)
+ if (!policy) {
+ RecordRequestOutcome(RequestOutcome::DISCARDED_NO_ORIGIN_POLICY);
return;
+ }
+
+ Error type = details.type;
+ // It is expected for Reporting uploads to terminate with ERR_ABORTED, since
+ // the ReportingUploader cancels them after receiving the response code and
+ // headers.
+ if (details.reporting_upload_depth > 0 && type == ERR_ABORTED) {
+ // TODO(juliatuttle): Modify ReportingUploader to drain successful uploads
+ // instead of aborting them, so NEL can properly report on aborted
+ // requests.
+ type = OK;
+ }
std::string type_string;
- if (!GetTypeFromNetError(details.type, &type_string))
+ if (!GetTypeFromNetError(type, &type_string)) {
+ RecordRequestOutcome(RequestOutcome::DISCARDED_UNMAPPED_ERROR);
return;
+ }
if (IsHttpError(details))
type_string = kHttpErrorType;
- double sampling_fraction = RequestWasSuccessful(details)
- ? policy->success_fraction
- : policy->failure_fraction;
- if (base::RandDouble() >= sampling_fraction)
+ // This check would go earlier, but the histogram bucket will be more
+ // meaningful if it only includes reports that otherwise could have been
+ // uploaded.
+ if (details.reporting_upload_depth > kMaxNestedReportDepth) {
+ RecordRequestOutcome(RequestOutcome::DISCARDED_REPORTING_UPLOAD);
return;
+ }
+
+ bool success = (type == OK) && !IsHttpError(details);
+ double sampling_fraction =
+ success ? policy->success_fraction : policy->failure_fraction;
+ if (base::RandDouble() >= sampling_fraction) {
+ RecordRequestOutcome(success
+ ? RequestOutcome::DISCARDED_UNSAMPLED_SUCCESS
+ : RequestOutcome::DISCARDED_UNSAMPLED_FAILURE);
+ return;
+ }
reporting_service_->QueueReport(
details.uri, policy->report_to, kReportType,
- CreateReportBody(type_string, sampling_fraction, details));
+ CreateReportBody(type_string, sampling_fraction, details),
+ details.reporting_upload_depth);
+ RecordRequestOutcome(RequestOutcome::QUEUED);
}
void RemoveBrowsingData(const base::RepeatingCallback<bool(const GURL&)>&
@@ -234,7 +311,8 @@ class NetworkErrorLoggingServiceImpl : public NetworkErrorLoggingService {
// Would be unordered_map, but url::Origin has no hash.
using PolicyMap = std::map<url::Origin, OriginPolicy>;
- // Wildcard policies are policies for which the includeSubdomains flag is set.
+ // Wildcard policies are policies for which the include-subdomains flag is
+ // set.
//
// Wildcard policies are accessed by domain name, not full origin, so there
// can be multiple wildcard policies per domain name.
@@ -252,29 +330,41 @@ class NetworkErrorLoggingServiceImpl : public NetworkErrorLoggingService {
PolicyMap policies_;
WildcardPolicyMap wildcard_policies_;
- bool ParseHeader(const std::string& json_value,
- base::TimeTicks now_ticks,
- OriginPolicy* policy_out) const {
+ HeaderOutcome ParseHeader(const std::string& json_value,
+ base::TimeTicks now_ticks,
+ OriginPolicy* policy_out) const {
DCHECK(policy_out);
- std::unique_ptr<base::Value> value = base::JSONReader::Read(json_value);
+ if (json_value.size() > kMaxJsonSize)
+ return HeaderOutcome::DISCARDED_JSON_TOO_BIG;
+
+ std::unique_ptr<base::Value> value =
+ base::JSONReader::Read(json_value, base::JSON_PARSE_RFC, kMaxJsonDepth);
if (!value)
- return false;
+ return HeaderOutcome::DISCARDED_JSON_INVALID;
const base::DictionaryValue* dict = nullptr;
if (!value->GetAsDictionary(&dict))
- return false;
+ return HeaderOutcome::DISCARDED_NOT_DICTIONARY;
+ if (!dict->HasKey(kMaxAgeKey))
+ return HeaderOutcome::DISCARDED_TTL_MISSING;
int max_age_sec;
- if (!dict->GetInteger(kMaxAgeKey, &max_age_sec) || max_age_sec < 0)
- return false;
+ if (!dict->GetInteger(kMaxAgeKey, &max_age_sec))
+ return HeaderOutcome::DISCARDED_TTL_NOT_INTEGER;
+ if (max_age_sec < 0)
+ return HeaderOutcome::DISCARDED_TTL_NEGATIVE;
std::string report_to;
- if (!dict->GetString(kReportToKey, &report_to) && max_age_sec > 0)
- return false;
+ if (max_age_sec > 0) {
+ if (!dict->HasKey(kReportToKey))
+ return HeaderOutcome::DISCARDED_REPORT_TO_MISSING;
+ if (!dict->GetString(kReportToKey, &report_to))
+ return HeaderOutcome::DISCARDED_REPORT_TO_NOT_STRING;
+ }
bool include_subdomains = false;
- // includeSubdomains is optional and defaults to false, so it's okay if
+ // include-subdomains is optional and defaults to false, so it's okay if
// GetBoolean fails.
dict->GetBoolean(kIncludeSubdomainsKey, &include_subdomains);
@@ -289,17 +379,17 @@ class NetworkErrorLoggingServiceImpl : public NetworkErrorLoggingService {
dict->GetDouble(kFailureFractionKey, &failure_fraction);
policy_out->report_to = report_to;
+ policy_out->include_subdomains = include_subdomains;
+ policy_out->success_fraction = success_fraction;
+ policy_out->failure_fraction = failure_fraction;
if (max_age_sec > 0) {
policy_out->expires =
now_ticks + base::TimeDelta::FromSeconds(max_age_sec);
+ return HeaderOutcome::SET;
} else {
policy_out->expires = base::TimeTicks();
+ return HeaderOutcome::REMOVED;
}
- policy_out->include_subdomains = include_subdomains;
- policy_out->success_fraction = success_fraction;
- policy_out->failure_fraction = failure_fraction;
-
- return true;
}
const OriginPolicy* FindPolicyForOrigin(const url::Origin& origin) const {
@@ -331,7 +421,7 @@ class NetworkErrorLoggingServiceImpl : public NetworkErrorLoggingService {
// TODO(juliatuttle): Come up with a deterministic way to resolve these.
if (it->second.size() > 1) {
LOG(WARNING) << "Domain " << domain
- << " matches multiple origins with includeSubdomains; "
+ << " matches multiple origins with include-subdomains; "
<< "choosing one arbitrarily.";
}
@@ -384,10 +474,7 @@ class NetworkErrorLoggingServiceImpl : public NetworkErrorLoggingService {
body->SetString(kReferrerKey, details.referrer.spec());
body->SetDouble(kSamplingFractionKey, sampling_fraction);
body->SetString(kServerIpKey, details.server_ip.ToString());
- std::string protocol = NextProtoToString(details.protocol);
- if (protocol == "unknown")
- protocol = "";
- body->SetString(kProtocolKey, protocol);
+ body->SetString(kProtocolKey, details.protocol);
body->SetInteger(kStatusCodeKey, details.status_code);
body->SetInteger(kElapsedTimeKey, details.elapsed_time.InMilliseconds());
body->SetString(kTypeKey, type);
@@ -406,9 +493,21 @@ NetworkErrorLoggingService::RequestDetails::RequestDetails(
const RequestDetails& other) = default;
NetworkErrorLoggingService::RequestDetails::~RequestDetails() = default;
+
+// static:
+
const char NetworkErrorLoggingService::kHeaderName[] = "NEL";
const char NetworkErrorLoggingService::kReportType[] = "network-error";
+
+// Allow NEL reports on regular requests, plus NEL reports on Reporting uploads
+// containing only regular requests, but do not allow NEL reports on Reporting
+// uploads containing Reporting uploads.
+//
+// This prevents origins from building purposefully-broken Reporting endpoints
+// that generate new NEL reports to bypass the age limit on Reporting reports.
+const int NetworkErrorLoggingService::kMaxNestedReportDepth = 1;
+
const char NetworkErrorLoggingService::kUriKey[] = "uri";
const char NetworkErrorLoggingService::kReferrerKey[] = "referrer";
const char NetworkErrorLoggingService::kSamplingFractionKey[] =
@@ -420,6 +519,30 @@ const char NetworkErrorLoggingService::kElapsedTimeKey[] = "elapsed-time";
const char NetworkErrorLoggingService::kTypeKey[] = "type";
// static
+void NetworkErrorLoggingService::
+ RecordHeaderDiscardedForNoNetworkErrorLoggingService() {
+ RecordHeaderOutcome(
+ HeaderOutcome::DISCARDED_NO_NETWORK_ERROR_LOGGING_SERVICE);
+}
+
+// static
+void NetworkErrorLoggingService::RecordHeaderDiscardedForInvalidSSLInfo() {
+ RecordHeaderOutcome(HeaderOutcome::DISCARDED_INVALID_SSL_INFO);
+}
+
+// static
+void NetworkErrorLoggingService::RecordHeaderDiscardedForCertStatusError() {
+ RecordHeaderOutcome(HeaderOutcome::DISCARDED_CERT_STATUS_ERROR);
+}
+
+// static
+void NetworkErrorLoggingService::
+ RecordRequestDiscardedForNoNetworkErrorLoggingService() {
+ RecordRequestOutcome(
+ RequestOutcome::DISCARDED_NO_NETWORK_ERROR_LOGGING_SERVICE);
+}
+
+// static
std::unique_ptr<NetworkErrorLoggingService> NetworkErrorLoggingService::Create(
std::unique_ptr<NetworkErrorLoggingDelegate> delegate) {
return std::make_unique<NetworkErrorLoggingServiceImpl>(std::move(delegate));
@@ -433,7 +556,7 @@ void NetworkErrorLoggingService::SetReportingService(
}
void NetworkErrorLoggingService::SetTickClockForTesting(
- base::TickClock* tick_clock) {
+ const base::TickClock* tick_clock) {
tick_clock_ = tick_clock;
}
diff --git a/chromium/net/network_error_logging/network_error_logging_service.h b/chromium/net/network_error_logging/network_error_logging_service.h
index 3a7613f8b76..a25c0eea30a 100644
--- a/chromium/net/network_error_logging/network_error_logging_service.h
+++ b/chromium/net/network_error_logging/network_error_logging_service.h
@@ -17,7 +17,6 @@
#include "net/base/ip_address.h"
#include "net/base/net_errors.h"
#include "net/base/net_export.h"
-#include "net/socket/next_proto.h"
#include "url/gurl.h"
#include "url/origin.h"
@@ -51,18 +50,27 @@ class NET_EXPORT NetworkErrorLoggingService {
GURL uri;
GURL referrer;
IPAddress server_ip;
- NextProto protocol;
+ std::string protocol;
int status_code;
base::TimeDelta elapsed_time;
Error type;
- bool is_reporting_upload;
+ // 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;
};
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 kUriKey[];
@@ -74,6 +82,12 @@ class NET_EXPORT NetworkErrorLoggingService {
static const char kElapsedTimeKey[];
static const char kTypeKey[];
+ static void RecordHeaderDiscardedForNoNetworkErrorLoggingService();
+ static void RecordHeaderDiscardedForInvalidSSLInfo();
+ static void RecordHeaderDiscardedForCertStatusError();
+
+ static void RecordRequestDiscardedForNoNetworkErrorLoggingService();
+
static std::unique_ptr<NetworkErrorLoggingService> Create(
std::unique_ptr<NetworkErrorLoggingDelegate> delegate);
@@ -104,13 +118,13 @@ class NET_EXPORT NetworkErrorLoggingService {
// Sets a base::TickClock (used to track policy expiration) for tests.
// |tick_clock| must outlive the NetworkErrorLoggingService, and cannot be
// nullptr.
- void SetTickClockForTesting(base::TickClock* tick_clock);
+ void SetTickClockForTesting(const base::TickClock* tick_clock);
protected:
NetworkErrorLoggingService();
// Unowned:
- base::TickClock* tick_clock_;
+ const base::TickClock* tick_clock_;
ReportingService* reporting_service_;
private:
diff --git a/chromium/net/network_error_logging/network_error_logging_service_unittest.cc b/chromium/net/network_error_logging/network_error_logging_service_unittest.cc
index ac08be0614c..a1051402314 100644
--- a/chromium/net/network_error_logging/network_error_logging_service_unittest.cc
+++ b/chromium/net/network_error_logging/network_error_logging_service_unittest.cc
@@ -18,7 +18,6 @@
#include "net/network_error_logging/network_error_logging_service.h"
#include "net/reporting/reporting_policy.h"
#include "net/reporting/reporting_service.h"
-#include "net/socket/next_proto.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
#include "url/origin.h"
@@ -35,13 +34,19 @@ class TestReportingService : public ReportingService {
: url(other.url),
group(other.group),
type(other.type),
- body(std::move(other.body)) {}
+ body(std::move(other.body)),
+ depth(other.depth) {}
Report(const GURL& url,
const std::string& group,
const std::string& type,
- std::unique_ptr<const base::Value> body)
- : url(url), group(group), type(type), body(std::move(body)) {}
+ std::unique_ptr<const base::Value> body,
+ int depth)
+ : url(url),
+ group(group),
+ type(type),
+ body(std::move(body)),
+ depth(depth) {}
~Report() = default;
@@ -49,6 +54,7 @@ class TestReportingService : public ReportingService {
std::string group;
std::string type;
std::unique_ptr<const base::Value> body;
+ int depth;
private:
DISALLOW_COPY(Report);
@@ -65,8 +71,9 @@ class TestReportingService : public ReportingService {
void QueueReport(const GURL& url,
const std::string& group,
const std::string& type,
- std::unique_ptr<const base::Value> body) override {
- reports_.push_back(Report(url, group, type, std::move(body)));
+ std::unique_ptr<const base::Value> body,
+ int depth) override {
+ reports_.push_back(Report(url, group, type, std::move(body), depth));
}
void ProcessHeader(const GURL& url,
@@ -80,9 +87,9 @@ class TestReportingService : public ReportingService {
NOTREACHED();
}
- bool RequestIsUpload(const URLRequest& request) override {
+ int GetUploadDepth(const URLRequest& request) override {
NOTREACHED();
- return true;
+ return 0;
}
const ReportingPolicy& GetPolicy() const override {
@@ -126,11 +133,10 @@ class NetworkErrorLoggingServiceTest : public ::testing::Test {
details.uri = url;
details.referrer = kReferrer_;
details.server_ip = IPAddress::IPv4AllZeros();
- details.protocol = kProtoUnknown;
details.status_code = status_code;
details.elapsed_time = base::TimeDelta::FromSeconds(1);
details.type = error_type;
- details.is_reporting_upload = false;
+ details.reporting_upload_depth = 0;
return details;
}
@@ -154,8 +160,14 @@ class NetworkErrorLoggingServiceTest : public ::testing::Test {
const std::string kHeader_ = "{\"report-to\":\"group\",\"max-age\":86400}";
const std::string kHeaderIncludeSubdomains_ =
- "{\"report-to\":\"group\",\"max-age\":86400,\"includeSubdomains\":true}";
+ "{\"report-to\":\"group\",\"max-age\":86400,\"include-subdomains\":true}";
const std::string kHeaderMaxAge0_ = "{\"max-age\":0}";
+ const std::string kHeaderTooLong_ =
+ "{\"report-to\":\"group\",\"max-age\":86400,\"junk\":\"" +
+ std::string(32 * 1024, 'a') + "\"}";
+ const std::string kHeaderTooDeep_ =
+ "{\"report-to\":\"group\",\"max-age\":86400,\"junk\":[[[[[[[[[[]]]]]]]]]]"
+ "}";
const std::string kGroup_ = "group";
@@ -207,6 +219,22 @@ TEST_F(NetworkErrorLoggingServiceTest, NoPolicyForOrigin) {
EXPECT_TRUE(reports().empty());
}
+TEST_F(NetworkErrorLoggingServiceTest, JsonTooLong) {
+ service()->OnHeader(kOrigin_, kHeaderTooLong_);
+
+ service()->OnRequest(MakeRequestDetails(kUrl_, ERR_CONNECTION_REFUSED));
+
+ EXPECT_TRUE(reports().empty());
+}
+
+TEST_F(NetworkErrorLoggingServiceTest, JsonTooDeep) {
+ service()->OnHeader(kOrigin_, kHeaderTooDeep_);
+
+ service()->OnRequest(MakeRequestDetails(kUrl_, ERR_CONNECTION_REFUSED));
+
+ EXPECT_TRUE(reports().empty());
+}
+
TEST_F(NetworkErrorLoggingServiceTest, SuccessReportQueued) {
static const std::string kHeaderSuccessFraction1 =
"{\"report-to\":\"group\",\"max-age\":86400,\"success-fraction\":1.0}";
@@ -218,6 +246,7 @@ TEST_F(NetworkErrorLoggingServiceTest, SuccessReportQueued) {
EXPECT_EQ(kUrl_, reports()[0].url);
EXPECT_EQ(kGroup_, reports()[0].group);
EXPECT_EQ(kType_, reports()[0].type);
+ EXPECT_EQ(0, reports()[0].depth);
const base::DictionaryValue* body;
ASSERT_TRUE(reports()[0].body->GetAsDictionary(&body));
@@ -251,6 +280,7 @@ TEST_F(NetworkErrorLoggingServiceTest, FailureReportQueued) {
EXPECT_EQ(kUrl_, reports()[0].url);
EXPECT_EQ(kGroup_, reports()[0].group);
EXPECT_EQ(kType_, reports()[0].type);
+ EXPECT_EQ(0, reports()[0].depth);
const base::DictionaryValue* body;
ASSERT_TRUE(reports()[0].body->GetAsDictionary(&body));
@@ -284,6 +314,7 @@ TEST_F(NetworkErrorLoggingServiceTest, HttpErrorReportQueued) {
EXPECT_EQ(kUrl_, reports()[0].url);
EXPECT_EQ(kGroup_, reports()[0].group);
EXPECT_EQ(kType_, reports()[0].type);
+ EXPECT_EQ(0, reports()[0].depth);
const base::DictionaryValue* body;
ASSERT_TRUE(reports()[0].body->GetAsDictionary(&body));
@@ -486,5 +517,31 @@ TEST_F(NetworkErrorLoggingServiceTest, RemoveSomeBrowsingData) {
ASSERT_EQ(1u, reports().size());
}
+TEST_F(NetworkErrorLoggingServiceTest, Nested) {
+ service()->OnHeader(kOrigin_, kHeader_);
+
+ NetworkErrorLoggingService::RequestDetails details =
+ MakeRequestDetails(kUrl_, ERR_CONNECTION_REFUSED);
+ details.reporting_upload_depth =
+ NetworkErrorLoggingService::kMaxNestedReportDepth;
+ service()->OnRequest(details);
+
+ ASSERT_EQ(1u, reports().size());
+ EXPECT_EQ(NetworkErrorLoggingService::kMaxNestedReportDepth,
+ reports()[0].depth);
+}
+
+TEST_F(NetworkErrorLoggingServiceTest, NestedTooDeep) {
+ service()->OnHeader(kOrigin_, kHeader_);
+
+ NetworkErrorLoggingService::RequestDetails details =
+ MakeRequestDetails(kUrl_, ERR_CONNECTION_REFUSED);
+ details.reporting_upload_depth =
+ NetworkErrorLoggingService::kMaxNestedReportDepth + 1;
+ service()->OnRequest(details);
+
+ EXPECT_TRUE(reports().empty());
+}
+
} // namespace
} // namespace net