Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(65)

Side by Side Diff: chrome/browser/safe_browsing/notification_image_reporter.cc

Issue 2624193004: Submit a sample of notification images to Safe Browsing (Closed)
Patch Set: Report net_error codes to UMA Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/safe_browsing/notification_image_reporter.h"
6
7 #include <cmath>
8 #include <vector>
9
10 #include "base/bind.h"
11 #include "base/logging.h"
12 #include "base/memory/ptr_util.h"
13 #include "base/memory/ref_counted_memory.h"
14 #include "base/metrics/histogram_macros.h"
15 #include "base/rand_util.h"
16 #include "base/threading/sequenced_worker_pool.h"
17 #include "chrome/browser/browser_process.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
20 #include "chrome/common/safe_browsing/csd.pb.h"
21 #include "components/safe_browsing_db/database_manager.h"
22 #include "components/safe_browsing_db/safe_browsing_prefs.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "net/base/net_errors.h"
25 #include "net/url_request/report_sender.h"
26 #include "skia/ext/image_operations.h"
27 #include "third_party/skia/include/core/SkBitmap.h"
28 #include "ui/gfx/codec/png_codec.h"
29 #include "ui/gfx/geometry/size.h"
30 #include "url/gurl.h"
31
32 using content::BrowserThread;
33
34 namespace safe_browsing {
35
36 namespace {
37
38 const size_t kMaxReportsPerDay = 5;
39
40 void LogReportResult(const GURL& url, int net_error) {
41 UMA_HISTOGRAM_SPARSE_SLOWLY("SafeBrowsing.NotificationImageReporter.NetError",
42 net_error);
43 }
44
45 } // namespace
46
47 const char NotificationImageReporter::kReportingUploadUrl[] =
48 "https://safebrowsing.googleusercontent.com/safebrowsing/clientreport/"
49 "chrome-notification-image"; // TODO(johnme): Confirm URL.
50
51 NotificationImageReporter::NotificationImageReporter(
52 net::URLRequestContext* request_context)
53 : NotificationImageReporter(base::MakeUnique<net::ReportSender>(
54 request_context,
55 net::ReportSender::CookiesPreference::DO_NOT_SEND_COOKIES)) {}
56
57 NotificationImageReporter::NotificationImageReporter(
58 std::unique_ptr<net::ReportSender> report_sender)
59 : report_sender_(std::move(report_sender)), weak_factory_on_io_(this) {
60 DCHECK_CURRENTLY_ON(BrowserThread::IO);
61 }
62
63 NotificationImageReporter::~NotificationImageReporter() {
64 DCHECK_CURRENTLY_ON(BrowserThread::IO);
65 }
66
67 void NotificationImageReporter::ReportNotificationImageOnIO(
68 Profile* profile,
69 const scoped_refptr<SafeBrowsingDatabaseManager>& database_manager,
70 const GURL& origin,
71 const SkBitmap& image) {
72 DCHECK_CURRENTLY_ON(BrowserThread::IO);
73 DCHECK(profile);
74 DCHECK_EQ(origin, origin.GetOrigin());
75 DCHECK(origin.is_valid());
76
77 // Skip whitelisted origins to cut down on report volume.
78 if (!database_manager || database_manager->MatchCsdWhitelistUrl(origin)) {
79 SkippedReporting();
80 return;
81 }
82
83 // Sample a Finch-controlled fraction only.
84 double report_chance = GetReportChance();
85 if (base::RandDouble() >= report_chance) {
86 SkippedReporting();
87 return;
88 }
89
90 // Avoid exceeding kMaxReportsPerDay.
91 base::Time a_day_ago = base::Time::Now() - base::TimeDelta::FromDays(1);
92 while (!report_times_.empty() &&
93 report_times_.front() < /* older than */ a_day_ago) {
94 report_times_.pop();
95 }
96 if (report_times_.size() >= kMaxReportsPerDay) {
97 SkippedReporting();
98 return;
99 }
100 // n.b. we write to report_times_ here even if we'll later end up skipping
101 // reporting because GetExtendedReportingLevel was not SBER_LEVEL_SCOUT. That
102 // saves us two thread hops, with the downside that we may underreport
103 // notifications on the first day that a user opts in to SBER_LEVEL_SCOUT.
104 report_times_.push(base::Time::Now());
105
106 BrowserThread::PostTask(
107 BrowserThread::UI, FROM_HERE,
108 base::Bind(&NotificationImageReporter::ReportNotificationImageOnUI,
109 weak_factory_on_io_.GetWeakPtr(), profile, origin, image));
110 }
111
112 double NotificationImageReporter::GetReportChance() {
113 DCHECK_CURRENTLY_ON(BrowserThread::IO);
114 return 0.2; // TODO(johnme): Get this from Finch.
115 }
116
117 void NotificationImageReporter::SkippedReporting() {}
118
119 // static
120 void NotificationImageReporter::ReportNotificationImageOnUI(
121 const base::WeakPtr<NotificationImageReporter>& weak_this_on_io,
122 Profile* profile,
123 const GURL& origin,
124 const SkBitmap& image) {
125 DCHECK_CURRENTLY_ON(BrowserThread::UI);
126
127 // Skip reporting unless SBER2 Scout is enabled.
128 switch (GetExtendedReportingLevel(*profile->GetPrefs())) {
129 case SBER_LEVEL_OFF:
130 case SBER_LEVEL_LEGACY:
131 BrowserThread::PostTask(
132 BrowserThread::IO, FROM_HERE,
133 base::Bind(&NotificationImageReporter::SkippedReporting,
134 weak_this_on_io));
135 return;
136 case SBER_LEVEL_SCOUT:
137 break;
138 }
139
140 BrowserThread::GetBlockingPool()->PostWorkerTask(
141 FROM_HERE,
142 base::Bind(
143 &NotificationImageReporter::DownscaleNotificationImageOnBlockingPool,
144 weak_this_on_io, origin, image));
145 }
146
147 // static
148 void NotificationImageReporter::DownscaleNotificationImageOnBlockingPool(
149 const base::WeakPtr<NotificationImageReporter>& weak_this_on_io,
150 const GURL& origin,
151 const SkBitmap& image) {
152 DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
153
154 // Downscale to fit within 512x512. TODO(johnme): Get this from Finch.
155 const double MAX_SIZE = 512;
156 double scale = std::min(MAX_SIZE / image.width(), MAX_SIZE / image.height());
157 SkBitmap downscaled_image =
158 scale >= 1.0 ? image // already small enough
159 : skia::ImageOperations::Resize(
160 image, skia::ImageOperations::RESIZE_GOOD,
161 std::lround(scale * image.width()),
162 std::lround(scale * image.height()));
163
164 // Encode as PNG.
165 std::vector<unsigned char> png_bytes;
166 if (!gfx::PNGCodec::EncodeBGRASkBitmap(downscaled_image, false, &png_bytes)) {
167 NOTREACHED();
168 return;
169 }
170
171 BrowserThread::PostTask(
172 BrowserThread::IO, FROM_HERE,
173 base::Bind(&NotificationImageReporter::SendReportOnIO, weak_this_on_io,
174 origin, base::RefCountedBytes::TakeVector(&png_bytes),
175 gfx::Size(downscaled_image.width(), downscaled_image.height()),
176 gfx::Size(image.width(), image.height())));
177 }
178
179 void NotificationImageReporter::SendReportOnIO(
180 const GURL& origin,
181 scoped_refptr<base::RefCountedMemory> png_data,
182 const gfx::Size& dimensions,
183 const gfx::Size& original_dimensions) {
184 DCHECK_CURRENTLY_ON(BrowserThread::IO);
185
186 NotificationImageReportRequest report;
187 report.set_notification_origin(origin.spec());
188 report.mutable_image()->set_png_data(png_data->front(), png_data->size());
189 report.mutable_image()->mutable_dimensions()->set_width(dimensions.width());
190 report.mutable_image()->mutable_dimensions()->set_height(dimensions.height());
191 if (dimensions != original_dimensions) {
192 report.mutable_image()->mutable_original_dimensions()->set_width(
193 original_dimensions.width());
194 report.mutable_image()->mutable_original_dimensions()->set_height(
195 original_dimensions.height());
196 }
197
198 std::string serialized_report;
199 report.SerializeToString(&serialized_report);
200 report_sender_->Send(
201 GURL(kReportingUploadUrl), "application/octet-stream", serialized_report,
202 base::Bind(&LogReportResult, GURL(kReportingUploadUrl), net::OK),
203 base::Bind(&LogReportResult));
204 // TODO(johnme): Consider logging bandwidth and/or duration to UMA.
205 }
206
207 } // namespace safe_browsing
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698