Add TOO_MANY_REQUESTS to BinaryUploadService::Result
This adds a new enum value to handle 429 errors so they can be used to
throttle multi-file uploads. The following changes are made in this CL
to achieve this:
- BinaryUploadService and MultipartUploadRequest are updated to handle
the new result.
- ContentAnalysisDelegate is update so no more files are uploaded in
a multi-file upload case.
- Histograms are updated so data about this new case can be collected.
Bug: 1191062
Change-Id: Ie6794d2a48739a9216ca7493e038e714ca70b822
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2785163
Reviewed-by: Steven Holte <holte@chromium.org>
Reviewed-by: Roger Tawa <rogerta@chromium.org>
Reviewed-by: Daniel Rubery <drubery@chromium.org>
Auto-Submit: Dominique Fauteux-Chapleau <domfc@chromium.org>
Commit-Queue: Dominique Fauteux-Chapleau <domfc@chromium.org>
Cr-Commit-Position: refs/heads/master@{#869534}
diff --git a/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.cc b/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.cc
index b087f138..fe88383 100644
--- a/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.cc
+++ b/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.cc
@@ -236,6 +236,7 @@
case BinaryUploadService::Result::UPLOAD_FAILURE:
case BinaryUploadService::Result::TIMEOUT:
case BinaryUploadService::Result::FAILED_TO_GET_TOKEN:
+ case BinaryUploadService::Result::TOO_MANY_REQUESTS:
// UNAUTHORIZED allows data usage since it's a result only obtained if the
// browser is not authorized to perform deep scanning. It does not make
// sense to block data in this situation since no actual scanning of the
@@ -447,6 +448,9 @@
base::FilePath path,
BinaryUploadService::Result result,
enterprise_connectors::ContentAnalysisResponse response) {
+ if (result == BinaryUploadService::Result::TOO_MANY_REQUESTS)
+ throttled_ = true;
+
// Find the path in the set of files that are being scanned.
auto it = std::find(data_.paths.begin(), data_.paths.end(), path);
DCHECK(it != data_.paths.end());
@@ -611,6 +615,14 @@
return;
}
+ // If |throttled_| is true, then the file shouldn't be upload since the server
+ // is receiving too many requests.
+ if (throttled_) {
+ request->FinishRequest(BinaryUploadService::Result::TOO_MANY_REQUESTS,
+ enterprise_connectors::ContentAnalysisResponse());
+ return;
+ }
+
UploadFileForDeepScanning(result, data_.paths[index], std::move(request));
}
diff --git a/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.h b/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.h
index fbab5d6..a6b257e 100644
--- a/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.h
+++ b/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.h
@@ -360,6 +360,10 @@
// for every file/text. This is read to ensure |this| isn't deleted too early.
bool data_uploaded_ = false;
+ // This is set to true as soon as a TOO_MANY_REQUESTS response is obtained. No
+ // more data should be upload for |this| at that point.
+ bool throttled_ = false;
+
base::TimeTicks upload_start_time_;
base::WeakPtrFactory<ContentAnalysisDelegate> weak_ptr_factory_{this};
diff --git a/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate_browsertest.cc b/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate_browsertest.cc
index cd17970..25ca4be 100644
--- a/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate_browsertest.cc
+++ b/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate_browsertest.cc
@@ -511,6 +511,84 @@
ASSERT_EQ(FakeBinaryUploadServiceStorage()->requests_count(), 2);
}
+IN_PROC_BROWSER_TEST_P(ContentAnalysisDelegateBrowserTest, Throttled) {
+ base::ScopedAllowBlockingForTesting allow_blocking;
+
+ // Set up delegate and upload service.
+ EnableUploadsScanningAndReporting();
+
+ ContentAnalysisDelegate::SetFactoryForTesting(
+ base::BindRepeating(&MinimalFakeContentAnalysisDelegate::Create));
+
+ FakeBinaryUploadServiceStorage()->SetAuthorized(true);
+ FakeBinaryUploadServiceStorage()->SetShouldAutomaticallyAuthorize(true);
+
+ // Create the files to be opened and scanned.
+ ContentAnalysisDelegate::Data data;
+ CreateFilesForTest({"a.exe", "b.exe", "c.exe"},
+ {"a content", "b content", "c content"}, &data);
+ ASSERT_TRUE(ContentAnalysisDelegate::IsEnabled(
+ browser()->profile(), GURL(kTestUrl), &data, FILE_ATTACHED));
+
+ // The malware verdict means an event should be reported.
+ safe_browsing::EventReportValidator validator(client());
+ validator.ExpectUnscannedFileEvents(
+ /*url*/ "about:blank",
+ {
+ created_file_paths()[0].AsUTF8Unsafe(),
+ created_file_paths()[1].AsUTF8Unsafe(),
+ created_file_paths()[2].AsUTF8Unsafe(),
+ },
+ {
+ // printf "a content" | sha256sum | tr '[:lower:]' '[:upper:]'
+ "D2D2ACF640179223BF9E1EB43C5FBF854C4E50FFB6733BC3A9279D3FF7DE9BE1",
+ // printf "b content" | sha256sum | tr '[:lower:]' '[:upper:]'
+ "93CB3641ADD6A9A6619D7E2F304EBCF5160B2DB016B27C6E3D641C5306897224",
+ // printf "c content" | sha256sum | tr '[:lower:]' '[:upper:]'
+ "2E6D1C4A1F39A02562BF1505AD775C0323D7A04C0C37C9B29D25F532B9972080",
+ },
+ /*trigger*/ SafeBrowsingPrivateEventRouter::kTriggerFileUpload,
+ // TODO(crbug.com/1191060): Update this string when the event is supported
+ /*reason*/ "SERVICE_UNAVAILABLE",
+ /*mimetypes*/ ExeMimeTypes(),
+ /*size*/ 9,
+ /*result*/
+ safe_browsing::EventResultToString(safe_browsing::EventResult::ALLOWED),
+ /*username*/ kUserName);
+
+ // Only the first file should be uploaded since the other ones will be
+ // throttled.
+ FakeBinaryUploadServiceStorage()->SetResponseForFile(
+ "a.exe", BinaryUploadService::Result::TOO_MANY_REQUESTS,
+ ContentAnalysisResponse());
+
+ bool called = false;
+ base::RunLoop run_loop;
+ SetQuitClosure(run_loop.QuitClosure());
+
+ // Start test.
+ ContentAnalysisDelegate::CreateForWebContents(
+ browser()->tab_strip_model()->GetActiveWebContents(), std::move(data),
+ base::BindLambdaForTesting(
+ [&called](const ContentAnalysisDelegate::Data& data,
+ const ContentAnalysisDelegate::Result& result) {
+ ASSERT_TRUE(result.text_results.empty());
+ ASSERT_EQ(result.paths_results.size(), 3u);
+ for (bool result : result.paths_results)
+ ASSERT_TRUE(result);
+ called = true;
+ }),
+ safe_browsing::DeepScanAccessPoint::UPLOAD);
+
+ run_loop.Run();
+
+ EXPECT_TRUE(called);
+
+ // There should have been 1 request for the first file and 1 for
+ // authentication.
+ ASSERT_EQ(FakeBinaryUploadServiceStorage()->requests_count(), 2);
+}
+
// This class tests each of the blocking settings used in Connector policies:
// - block_until_verdict
// - block_password_protected
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.cc b/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.cc
index b46abd7f..0263c51 100644
--- a/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.cc
+++ b/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.cc
@@ -83,6 +83,8 @@
return "FILE_ENCRYPTED";
case BinaryUploadService::Result::DLP_SCAN_UNSUPPORTED_FILE_TYPE:
return "DLP_SCAN_UNSUPPORTED_FILE_TYPE";
+ case BinaryUploadService::Result::TOO_MANY_REQUESTS:
+ return "TOO_MANY_REQUESTS";
}
}
@@ -364,10 +366,17 @@
void BinaryUploadService::OnUploadComplete(Request* request,
bool success,
+ int http_status,
const std::string& response_data) {
if (!IsActive(request))
return;
+ if (http_status == net::HTTP_TOO_MANY_REQUESTS) {
+ FinishRequest(request, Result::TOO_MANY_REQUESTS,
+ enterprise_connectors::ContentAnalysisResponse());
+ return;
+ }
+
if (!success) {
FinishRequest(request, Result::UPLOAD_FAILURE,
enterprise_connectors::ContentAnalysisResponse());
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.h b/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.h
index ac4de13..ef9e17a 100644
--- a/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.h
+++ b/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.h
@@ -81,7 +81,11 @@
// The file's type is not supported and the file was not uploaded.
DLP_SCAN_UNSUPPORTED_FILE_TYPE = 8,
- kMaxValue = DLP_SCAN_UNSUPPORTED_FILE_TYPE,
+ // The server returned a 429 HTTP status indicating too many requests are
+ // being sent.
+ TOO_MANY_REQUESTS = 9,
+
+ kMaxValue = TOO_MANY_REQUESTS,
};
// Callbacks used to pass along the results of scanning. The response protos
@@ -244,6 +248,7 @@
void OnUploadComplete(Request* request,
bool success,
+ int http_status,
const std::string& response_data);
void OnGetResponse(Request* request,
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service_unittest.cc b/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service_unittest.cc
index 33d5c7b..85dea56 100644
--- a/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service_unittest.cc
+++ b/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service_unittest.cc
@@ -63,7 +63,8 @@
void Start() override {
std::string serialized_response;
response_.SerializeToString(&serialized_response);
- std::move(callback_).Run(should_succeed_, serialized_response);
+ std::move(callback_).Run(should_succeed_, should_succeed_ ? 200 : 401,
+ serialized_response);
}
private:
@@ -161,7 +162,7 @@
void ReceiveResponseFromUpload(BinaryUploadService::Request* request,
bool success,
const std::string& response) {
- service_->OnUploadComplete(request, success, response);
+ service_->OnUploadComplete(request, success, success ? 200 : 401, response);
}
void ServiceWithNoFCMConnection() {
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_test_utils.cc b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_test_utils.cc
index 76424db..e3a0c8b 100644
--- a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_test_utils.cc
+++ b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_test_utils.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_test_utils.h"
+#include "base/containers/flat_map.h"
#include "base/json/json_reader.h"
#include "base/strings/string_number_conversions.h"
#include "base/values.h"
@@ -48,8 +49,7 @@
const std::string& expected_username) {
event_key_ = SafeBrowsingPrivateEventRouter::kKeyUnscannedFileEvent;
url_ = expected_url;
- filename_ = expected_filename;
- sha256_ = expected_sha256;
+ filenames_and_hashes_[expected_filename] = expected_sha256;
mimetypes_ = expected_mimetypes;
trigger_ = expected_trigger;
unscanned_reason_ = expected_reason;
@@ -66,6 +66,37 @@
});
}
+void EventReportValidator::ExpectUnscannedFileEvents(
+ const std::string& expected_url,
+ const std::vector<const std::string>& expected_filenames,
+ const std::vector<const std::string>& expected_sha256s,
+ const std::string& expected_trigger,
+ const std::string& expected_reason,
+ const std::set<std::string>* expected_mimetypes,
+ int expected_content_size,
+ const std::string& expected_result,
+ const std::string& expected_username) {
+ DCHECK_EQ(expected_filenames.size(), expected_sha256s.size());
+ for (size_t i = 0; i < expected_filenames.size(); ++i)
+ filenames_and_hashes_[expected_filenames[i]] = expected_sha256s[i];
+
+ event_key_ = SafeBrowsingPrivateEventRouter::kKeyUnscannedFileEvent;
+ url_ = expected_url;
+ mimetypes_ = expected_mimetypes;
+ trigger_ = expected_trigger;
+ unscanned_reason_ = expected_reason;
+ content_size_ = expected_content_size;
+ result_ = expected_result;
+ username_ = expected_username;
+ EXPECT_CALL(*client_, UploadSecurityEventReport_(_, _, _, _))
+ .Times(expected_filenames.size())
+ .WillRepeatedly([this](content::BrowserContext* context,
+ bool include_device_info, base::Value& report,
+ base::OnceCallback<void(bool)>& callback) {
+ ValidateReport(&report);
+ });
+}
+
void EventReportValidator::ExpectDangerousDeepScanningResult(
const std::string& expected_url,
const std::string& expected_filename,
@@ -78,8 +109,7 @@
const std::string& expected_username) {
event_key_ = SafeBrowsingPrivateEventRouter::kKeyDangerousDownloadEvent;
url_ = expected_url;
- filename_ = expected_filename;
- sha256_ = expected_sha256;
+ filenames_and_hashes_[expected_filename] = expected_sha256;
threat_type_ = expected_threat_type;
mimetypes_ = expected_mimetypes;
trigger_ = expected_trigger;
@@ -110,8 +140,7 @@
event_key_ = SafeBrowsingPrivateEventRouter::kKeySensitiveDataEvent;
url_ = expected_url;
dlp_verdict_ = expected_dlp_verdict;
- filename_ = expected_filename;
- sha256_ = expected_sha256;
+ filenames_and_hashes_[expected_filename] = expected_sha256;
mimetypes_ = expected_mimetypes;
trigger_ = expected_trigger;
content_size_ = expected_content_size;
@@ -142,8 +171,7 @@
const std::string& expected_username) {
event_key_ = SafeBrowsingPrivateEventRouter::kKeyDangerousDownloadEvent;
url_ = expected_url;
- filename_ = expected_filename;
- sha256_ = expected_sha256;
+ filenames_and_hashes_[expected_filename] = expected_sha256;
threat_type_ = expected_threat_type;
trigger_ = expected_trigger;
mimetypes_ = expected_mimetypes;
@@ -184,8 +212,7 @@
const std::string& expected_username) {
event_key_ = SafeBrowsingPrivateEventRouter::kKeySensitiveDataEvent;
url_ = expected_url;
- filename_ = expected_filename;
- sha256_ = expected_sha256;
+ filenames_and_hashes_[expected_filename] = expected_sha256;
trigger_ = expected_trigger;
mimetypes_ = expected_mimetypes;
content_size_ = expected_content_size;
@@ -223,8 +250,7 @@
const std::string& expected_username) {
event_key_ = SafeBrowsingPrivateEventRouter::kKeyDangerousDownloadEvent;
url_ = expected_url;
- filename_ = expected_filename;
- sha256_ = expected_sha256;
+ filenames_and_hashes_[expected_filename] = expected_sha256;
threat_type_ = expected_threat_type;
mimetypes_ = expected_mimetypes;
trigger_ = expected_trigger;
@@ -261,9 +287,7 @@
// The event should match the expected values.
ValidateField(event, SafeBrowsingPrivateEventRouter::kKeyUrl, url_);
- ValidateField(event, SafeBrowsingPrivateEventRouter::kKeyFileName, filename_);
- ValidateField(event, SafeBrowsingPrivateEventRouter::kKeyDownloadDigestSha256,
- sha256_);
+ ValidateFilenameAndHash(event);
ValidateField(event, SafeBrowsingPrivateEventRouter::kKeyTrigger, trigger_);
ValidateField(event, SafeBrowsingPrivateEventRouter::kKeyContentSize,
content_size_);
@@ -316,6 +340,16 @@
expected_rule.rule_id());
}
+void EventReportValidator::ValidateFilenameAndHash(base::Value* value) {
+ const std::string* filename =
+ value->FindStringKey(SafeBrowsingPrivateEventRouter::kKeyFileName);
+ ASSERT_TRUE(filename);
+ ASSERT_TRUE(filenames_and_hashes_.count(*filename))
+ << "Mismatch in field " << SafeBrowsingPrivateEventRouter::kKeyFileName;
+ ValidateField(value, SafeBrowsingPrivateEventRouter::kKeyDownloadDigestSha256,
+ filenames_and_hashes_[*filename]);
+}
+
void EventReportValidator::ValidateField(
base::Value* value,
const std::string& field_key,
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_test_utils.h b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_test_utils.h
index 5e1898e..56bfd50 100644
--- a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_test_utils.h
+++ b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_test_utils.h
@@ -9,6 +9,7 @@
#include <string>
#include "base/callback.h"
+#include "base/containers/flat_map.h"
#include "base/optional.h"
#include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h"
#include "components/enterprise/common/proto/connectors.pb.h"
@@ -93,6 +94,17 @@
const std::string& expected_result,
const std::string& expected_username);
+ void ExpectUnscannedFileEvents(
+ const std::string& expected_url,
+ const std::vector<const std::string>& expected_filenames,
+ const std::vector<const std::string>& expected_sha256s,
+ const std::string& expected_trigger,
+ const std::string& expected_reason,
+ const std::set<std::string>* expected_mimetypes,
+ int expected_content_size,
+ const std::string& expected_result,
+ const std::string& expected_username);
+
void ExpectDangerousDownloadEvent(
const std::string& expected_url,
const std::string& expected_filename,
@@ -116,6 +128,7 @@
void ValidateDlpRule(base::Value* value,
const enterprise_connectors::ContentAnalysisResponse::
Result::TriggeredRule& expected_rule);
+ void ValidateFilenameAndHash(base::Value* value);
void ValidateField(base::Value* value,
const std::string& field_key,
const base::Optional<std::string>& expected_value);
@@ -130,8 +143,6 @@
std::string event_key_;
std::string url_;
- std::string filename_;
- std::string sha256_;
std::string trigger_;
base::Optional<enterprise_connectors::ContentAnalysisResponse::Result>
dlp_verdict_ = base::nullopt;
@@ -142,6 +153,11 @@
base::Optional<std::string> result_ = base::nullopt;
std::string username_;
+ // When multiple files generate events, we don't necessarily know in which
+ // order they will be reported. As such, we use a map to ensure all of them
+ // are called as expected.
+ base::flat_map<std::string, std::string> filenames_and_hashes_;
+
base::RepeatingClosure done_closure_;
};
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.cc b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.cc
index 7e33556..104a5e5 100644
--- a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.cc
+++ b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.cc
@@ -36,6 +36,8 @@
case BinaryUploadService::Result::UNKNOWN:
case BinaryUploadService::Result::UPLOAD_FAILURE:
case BinaryUploadService::Result::FAILED_TO_GET_TOKEN:
+ // TODO(crbug.com/1191060): Update this string when the event is supported.
+ case BinaryUploadService::Result::TOO_MANY_REQUESTS:
unscanned_reason = "SERVICE_UNAVAILABLE";
break;
case BinaryUploadService::Result::FILE_ENCRYPTED:
@@ -324,6 +326,8 @@
return "FileEncrypted";
case BinaryUploadService::Result::DLP_SCAN_UNSUPPORTED_FILE_TYPE:
return "DlpScanUnsupportedFileType";
+ case BinaryUploadService::Result::TOO_MANY_REQUESTS:
+ return "TooManyRequests";
}
}
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/multipart_uploader.cc b/chrome/browser/safe_browsing/cloud_content_scanning/multipart_uploader.cc
index a0f4ac7..04bfd04 100644
--- a/chrome/browser/safe_browsing/cloud_content_scanning/multipart_uploader.cc
+++ b/chrome/browser/safe_browsing/cloud_content_scanning/multipart_uploader.cc
@@ -133,13 +133,15 @@
base::UmaHistogramMediumTimes(
"SBMultipartUploader.SuccessfulUploadDuration",
base::Time::Now() - start_time_);
- std::move(callback_).Run(/*success=*/true, *response_body.get());
+ std::move(callback_).Run(/*success=*/true, response_code,
+ *response_body.get());
} else {
if (response_code < 500 || retry_count_ >= kMaxRetryAttempts) {
RecordUploadSuccessHistogram(/*success=*/false);
base::UmaHistogramMediumTimes("SBMultipartUploader.FailedUploadDuration",
base::Time::Now() - start_time_);
- std::move(callback_).Run(/*success=*/false, *response_body.get());
+ std::move(callback_).Run(/*success=*/false, response_code,
+ *response_body.get());
} else {
content::GetUIThreadTaskRunner({})->PostDelayedTask(
FROM_HERE,
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/multipart_uploader.h b/chrome/browser/safe_browsing/cloud_content_scanning/multipart_uploader.h
index b6b9690..d8e3a8c 100644
--- a/chrome/browser/safe_browsing/cloud_content_scanning/multipart_uploader.h
+++ b/chrome/browser/safe_browsing/cloud_content_scanning/multipart_uploader.h
@@ -29,8 +29,8 @@
// multipart protocol. This class is neither movable nor copyable.
class MultipartUploadRequest {
public:
- using Callback =
- base::OnceCallback<void(bool success, const std::string& response_data)>;
+ using Callback = base::OnceCallback<
+ void(bool success, int http_status, const std::string& response_data)>;
// Creates a MultipartUploadRequest, which will upload |data| to the given
// |base_url| with |metadata| attached.
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index ebc2ed8..c573b12 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -67848,6 +67848,7 @@
<int value="6" label="Unauthorized"/>
<int value="7" label="File encrypted"/>
<int value="8" label="Unsupported file type"/>
+ <int value="9" label="Too many requests"/>
</enum>
<enum name="SafeBrowsingDelayedWarningEvent">
diff --git a/tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml b/tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml
index ecb7c2f..381277f 100644
--- a/tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml
@@ -304,6 +304,17 @@
</summary>
</histogram>
+<histogram name="SafeBrowsing.DeepScan.Download.TooManyRequests.Duration"
+ units="ms" expires_after="2022-02-01">
+ <owner>domfc@chromium.org</owner>
+ <owner>webprotect-team@google.com</owner>
+ <summary>
+ This records the deep scanning duration of a user download request with a
+ TooManyRequests result. It is logged once for each binary upload with that
+ result.
+ </summary>
+</histogram>
+
<histogram name="SafeBrowsing.DeepScan.Download.Unknown.Duration" units="ms"
expires_after="2022-02-01">
<owner>domfc@chromium.org</owner>
@@ -425,6 +436,17 @@
</summary>
</histogram>
+<histogram name="SafeBrowsing.DeepScan.DragAndDrop.TooManyRequests.Duration"
+ units="ms" expires_after="2022-02-01">
+ <owner>domfc@chromium.org</owner>
+ <owner>webprotect-team@google.com</owner>
+ <summary>
+ This records the deep scanning duration of a user "drag and drop"
+ request with a TooManyRequests result. It is logged once for each binary
+ upload with that result.
+ </summary>
+</histogram>
+
<histogram name="SafeBrowsing.DeepScan.DragAndDrop.Unknown.Duration" units="ms"
expires_after="2022-02-01">
<owner>domfc@chromium.org</owner>
@@ -533,6 +555,17 @@
</summary>
</histogram>
+<histogram name="SafeBrowsing.DeepScan.Paste.TooManyRequests.Duration"
+ units="ms" expires_after="2022-02-01">
+ <owner>domfc@chromium.org</owner>
+ <owner>webprotect-team@google.com</owner>
+ <summary>
+ This records the deep scanning duration of a user paste request with a
+ TooManyRequests result. It is logged once for each binary upload with that
+ result.
+ </summary>
+</histogram>
+
<histogram name="SafeBrowsing.DeepScan.Paste.Unknown.Duration" units="ms"
expires_after="2022-02-01">
<owner>domfc@chromium.org</owner>
@@ -650,6 +683,17 @@
</summary>
</histogram>
+<histogram name="SafeBrowsing.DeepScan.Upload.TooManyRequests.Duration"
+ units="ms" expires_after="2022-02-01">
+ <owner>domfc@chromium.org</owner>
+ <owner>webprotect-team@google.com</owner>
+ <summary>
+ This records the deep scanning duration of a user upload request with a
+ TooManyRequests result. It is logged once for each binary upload with that
+ result.
+ </summary>
+</histogram>
+
<histogram name="SafeBrowsing.DeepScan.Upload.Unknown.Duration" units="ms"
expires_after="2022-02-01">
<owner>domfc@chromium.org</owner>