diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-05-15 10:20:33 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-05-15 10:28:57 +0000 |
commit | d17ea114e5ef69ad5d5d7413280a13e6428098aa (patch) | |
tree | 2c01a75df69f30d27b1432467cfe7c1467a498da /chromium/net/network_error_logging | |
parent | 8c5c43c7b138c9b4b0bf56d946e61d3bbc111bec (diff) | |
download | qtwebengine-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')
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 |