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

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

Issue 1414343007: Collect threat details for phishing and UwS (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: nit Created 5 years, 1 month 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
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 // 4 //
5 // Implementation of the MalwareDetails class. 5 // Implementation of the ThreatDetails class.
6 6
7 #include "chrome/browser/safe_browsing/threat_details.h" 7 #include "chrome/browser/safe_browsing/threat_details.h"
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/lazy_instance.h" 10 #include "base/lazy_instance.h"
11 #include "chrome/browser/profiles/profile.h" 11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/safe_browsing/report.pb.h" 12 #include "chrome/browser/safe_browsing/report.pb.h"
13 #include "chrome/browser/safe_browsing/threat_details_cache.h" 13 #include "chrome/browser/safe_browsing/threat_details_cache.h"
14 #include "chrome/browser/safe_browsing/threat_details_history.h" 14 #include "chrome/browser/safe_browsing/threat_details_history.h"
15 #include "chrome/common/safe_browsing/safebrowsing_messages.h" 15 #include "chrome/common/safe_browsing/safebrowsing_messages.h"
16 #include "content/public/browser/browser_thread.h" 16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/browser/navigation_controller.h" 17 #include "content/public/browser/navigation_controller.h"
18 #include "content/public/browser/navigation_entry.h" 18 #include "content/public/browser/navigation_entry.h"
19 #include "content/public/browser/render_view_host.h" 19 #include "content/public/browser/render_view_host.h"
20 #include "content/public/browser/web_contents.h" 20 #include "content/public/browser/web_contents.h"
21 #include "net/url_request/url_request_context_getter.h" 21 #include "net/url_request/url_request_context_getter.h"
22 22
23 using content::BrowserThread; 23 using content::BrowserThread;
24 using content::NavigationEntry; 24 using content::NavigationEntry;
25 using content::WebContents; 25 using content::WebContents;
26 using safe_browsing::ClientMalwareReportRequest; 26 using safe_browsing::ClientSafeBrowsingReportRequest;
27 27
28 // Keep in sync with KMaxNodes in renderer/safe_browsing/malware_dom_details 28 // Keep in sync with KMaxNodes in renderer/safe_browsing/threat_dom_details
29 static const uint32 kMaxDomNodes = 500; 29 static const uint32 kMaxDomNodes = 500;
30 30
31 // static 31 // static
32 ThreatDetailsFactory* ThreatDetails::factory_ = NULL; 32 ThreatDetailsFactory* ThreatDetails::factory_ = NULL;
33 33
34 namespace {
35
36 // Helper function that converts SBThreatType to
37 // ClientSafeBrowsingReportRequest::ReportType.
38 ClientSafeBrowsingReportRequest::ReportType GetReportTypeFromSBThreatType(
39 SBThreatType threat_type) {
40 switch (threat_type) {
41 case SB_THREAT_TYPE_URL_PHISHING:
42 return ClientSafeBrowsingReportRequest::URL_PHISHING;
43 case SB_THREAT_TYPE_URL_MALWARE:
44 return ClientSafeBrowsingReportRequest::URL_MALWARE;
45 case SB_THREAT_TYPE_URL_UNWANTED:
46 return ClientSafeBrowsingReportRequest::URL_UNWANTED;
47 case SB_THREAT_TYPE_BINARY_MALWARE_URL:
48 return ClientSafeBrowsingReportRequest::BINARY_MALWARE_URL;
49 case SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL:
50 return ClientSafeBrowsingReportRequest::CLIENT_SIDE_PHISHING_URL;
51 case SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL:
52 return ClientSafeBrowsingReportRequest::CLIENT_SIDE_MALWARE_URL;
53 default: // Gated by SafeBrowsingBlockingPage::ShouldReportThreatDetails.
54 NOTREACHED() << "We should not send report for threat type "
55 << threat_type;
56 return ClientSafeBrowsingReportRequest::UNKNOWN;
57 }
58 }
59
60 } // namespace
61
34 // The default ThreatDetailsFactory. Global, made a singleton so we 62 // The default ThreatDetailsFactory. Global, made a singleton so we
35 // don't leak it. 63 // don't leak it.
36 class ThreatDetailsFactoryImpl : public ThreatDetailsFactory { 64 class ThreatDetailsFactoryImpl : public ThreatDetailsFactory {
37 public: 65 public:
38 ThreatDetails* CreateThreatDetails( 66 ThreatDetails* CreateThreatDetails(
39 SafeBrowsingUIManager* ui_manager, 67 SafeBrowsingUIManager* ui_manager,
40 WebContents* web_contents, 68 WebContents* web_contents,
41 const SafeBrowsingUIManager::UnsafeResource& unsafe_resource) override { 69 const SafeBrowsingUIManager::UnsafeResource& unsafe_resource) override {
42 return new ThreatDetails(ui_manager, web_contents, unsafe_resource); 70 return new ThreatDetails(ui_manager, web_contents, unsafe_resource);
43 } 71 }
44 72
45 private: 73 private:
46 friend struct base::DefaultLazyInstanceTraits<ThreatDetailsFactoryImpl>; 74 friend struct base::DefaultLazyInstanceTraits<ThreatDetailsFactoryImpl>;
47 75
48 ThreatDetailsFactoryImpl() {} 76 ThreatDetailsFactoryImpl() {}
49 77
50 DISALLOW_COPY_AND_ASSIGN(ThreatDetailsFactoryImpl); 78 DISALLOW_COPY_AND_ASSIGN(ThreatDetailsFactoryImpl);
51 }; 79 };
52 80
53 static base::LazyInstance<ThreatDetailsFactoryImpl> 81 static base::LazyInstance<ThreatDetailsFactoryImpl>
54 g_malware_details_factory_impl = LAZY_INSTANCE_INITIALIZER; 82 g_threat_details_factory_impl = LAZY_INSTANCE_INITIALIZER;
55 83
56 // Create a ThreatDetails for the given tab. 84 // Create a ThreatDetails for the given tab.
57 /* static */ 85 /* static */
58 ThreatDetails* ThreatDetails::NewThreatDetails( 86 ThreatDetails* ThreatDetails::NewThreatDetails(
59 SafeBrowsingUIManager* ui_manager, 87 SafeBrowsingUIManager* ui_manager,
60 WebContents* web_contents, 88 WebContents* web_contents,
61 const UnsafeResource& resource) { 89 const UnsafeResource& resource) {
62 // Set up the factory if this has not been done already (tests do that 90 // Set up the factory if this has not been done already (tests do that
63 // before this method is called). 91 // before this method is called).
64 if (!factory_) 92 if (!factory_)
65 factory_ = g_malware_details_factory_impl.Pointer(); 93 factory_ = g_threat_details_factory_impl.Pointer();
66 return factory_->CreateThreatDetails(ui_manager, web_contents, resource); 94 return factory_->CreateThreatDetails(ui_manager, web_contents, resource);
67 } 95 }
68 96
69 // Create a ThreatDetails for the given tab. Runs in the UI thread. 97 // Create a ThreatDetails for the given tab. Runs in the UI thread.
70 ThreatDetails::ThreatDetails(SafeBrowsingUIManager* ui_manager, 98 ThreatDetails::ThreatDetails(SafeBrowsingUIManager* ui_manager,
71 content::WebContents* web_contents, 99 content::WebContents* web_contents,
72 const UnsafeResource& resource) 100 const UnsafeResource& resource)
73 : content::WebContentsObserver(web_contents), 101 : content::WebContentsObserver(web_contents),
74 profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())), 102 profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())),
75 request_context_getter_(profile_->GetRequestContext()), 103 request_context_getter_(profile_->GetRequestContext()),
76 ui_manager_(ui_manager), 104 ui_manager_(ui_manager),
77 resource_(resource), 105 resource_(resource),
78 cache_result_(false), 106 cache_result_(false),
79 cache_collector_(new ThreatDetailsCacheCollector), 107 cache_collector_(new ThreatDetailsCacheCollector),
80 redirects_collector_(new ThreatDetailsRedirectsCollector(profile_)) { 108 redirects_collector_(new ThreatDetailsRedirectsCollector(profile_)) {
81 StartCollection(); 109 StartCollection();
82 } 110 }
83 111
84 ThreatDetails::~ThreatDetails() {} 112 ThreatDetails::~ThreatDetails() {}
85 113
86 bool ThreatDetails::OnMessageReceived(const IPC::Message& message) { 114 bool ThreatDetails::OnMessageReceived(const IPC::Message& message) {
87 bool handled = true; 115 bool handled = true;
88 IPC_BEGIN_MESSAGE_MAP(ThreatDetails, message) 116 IPC_BEGIN_MESSAGE_MAP(ThreatDetails, message)
89 IPC_MESSAGE_HANDLER(SafeBrowsingHostMsg_MalwareDOMDetails, 117 IPC_MESSAGE_HANDLER(SafeBrowsingHostMsg_ThreatDOMDetails,
90 OnReceivedThreatDOMDetails) 118 OnReceivedThreatDOMDetails)
91 IPC_MESSAGE_UNHANDLED(handled = false) 119 IPC_MESSAGE_UNHANDLED(handled = false)
92 IPC_END_MESSAGE_MAP() 120 IPC_END_MESSAGE_MAP()
93 return handled; 121 return handled;
94 } 122 }
95 123
96 bool ThreatDetails::IsReportableUrl(const GURL& url) const { 124 bool ThreatDetails::IsReportableUrl(const GURL& url) const {
97 // TODO(panayiotis): also skip internal urls. 125 // TODO(panayiotis): also skip internal urls.
98 return url.SchemeIs("http") || url.SchemeIs("https"); 126 return url.SchemeIs("http") || url.SchemeIs("https");
99 } 127 }
100 128
101 // Looks for a Resource for the given url in resources_. If found, it 129 // Looks for a Resource for the given url in resources_. If found, it
102 // updates |resource|. Otherwise, it creates a new message, adds it to 130 // updates |resource|. Otherwise, it creates a new message, adds it to
103 // resources_ and updates |resource| to point to it. 131 // resources_ and updates |resource| to point to it.
104 // 132 //
105 ClientMalwareReportRequest::Resource* ThreatDetails::FindOrCreateResource( 133 ClientSafeBrowsingReportRequest::Resource* ThreatDetails::FindOrCreateResource(
106 const GURL& url) { 134 const GURL& url) {
107 safe_browsing::ResourceMap::iterator it = resources_.find(url.spec()); 135 safe_browsing::ResourceMap::iterator it = resources_.find(url.spec());
108 if (it != resources_.end()) 136 if (it != resources_.end())
109 return it->second.get(); 137 return it->second.get();
110 138
111 // Create the resource for |url|. 139 // Create the resource for |url|.
112 int id = resources_.size(); 140 int id = resources_.size();
113 linked_ptr<ClientMalwareReportRequest::Resource> new_resource( 141 linked_ptr<ClientSafeBrowsingReportRequest::Resource> new_resource(
114 new ClientMalwareReportRequest::Resource()); 142 new ClientSafeBrowsingReportRequest::Resource());
115 new_resource->set_url(url.spec()); 143 new_resource->set_url(url.spec());
116 new_resource->set_id(id); 144 new_resource->set_id(id);
117 resources_[url.spec()] = new_resource; 145 resources_[url.spec()] = new_resource;
118 return new_resource.get(); 146 return new_resource.get();
119 } 147 }
120 148
121 void ThreatDetails::AddUrl(const GURL& url, 149 void ThreatDetails::AddUrl(const GURL& url,
122 const GURL& parent, 150 const GURL& parent,
123 const std::string& tagname, 151 const std::string& tagname,
124 const std::vector<GURL>* children) { 152 const std::vector<GURL>* children) {
125 if (!url.is_valid() || !IsReportableUrl(url)) 153 if (!url.is_valid() || !IsReportableUrl(url))
126 return; 154 return;
127 155
128 // Find (or create) the resource for the url. 156 // Find (or create) the resource for the url.
129 ClientMalwareReportRequest::Resource* url_resource = 157 ClientSafeBrowsingReportRequest::Resource* url_resource =
130 FindOrCreateResource(url); 158 FindOrCreateResource(url);
131 if (!tagname.empty()) 159 if (!tagname.empty())
132 url_resource->set_tag_name(tagname); 160 url_resource->set_tag_name(tagname);
133 if (!parent.is_empty() && IsReportableUrl(parent)) { 161 if (!parent.is_empty() && IsReportableUrl(parent)) {
134 // Add the resource for the parent. 162 // Add the resource for the parent.
135 ClientMalwareReportRequest::Resource* parent_resource = 163 ClientSafeBrowsingReportRequest::Resource* parent_resource =
136 FindOrCreateResource(parent); 164 FindOrCreateResource(parent);
137 // Update the parent-child relation 165 // Update the parent-child relation
138 url_resource->set_parent_id(parent_resource->id()); 166 url_resource->set_parent_id(parent_resource->id());
139 } 167 }
140 if (children) { 168 if (children) {
141 for (std::vector<GURL>::const_iterator it = children->begin(); 169 for (std::vector<GURL>::const_iterator it = children->begin();
142 it != children->end(); ++it) { 170 it != children->end(); ++it) {
143 ClientMalwareReportRequest::Resource* child_resource = 171 ClientSafeBrowsingReportRequest::Resource* child_resource =
144 FindOrCreateResource(*it); 172 FindOrCreateResource(*it);
145 url_resource->add_child_ids(child_resource->id()); 173 url_resource->add_child_ids(child_resource->id());
146 } 174 }
147 } 175 }
148 } 176 }
149 177
150 void ThreatDetails::StartCollection() { 178 void ThreatDetails::StartCollection() {
151 DVLOG(1) << "Starting to compute malware details."; 179 DVLOG(1) << "Starting to compute threat details.";
152 report_.reset(new ClientMalwareReportRequest()); 180 report_.reset(new ClientSafeBrowsingReportRequest());
153 181
154 if (IsReportableUrl(resource_.url)) 182 if (IsReportableUrl(resource_.url)) {
155 report_->set_malware_url(resource_.url.spec()); 183 report_->set_url(resource_.url.spec());
184 report_->set_type(GetReportTypeFromSBThreatType(resource_.threat_type));
185 }
156 186
157 GURL page_url = web_contents()->GetURL(); 187 GURL page_url = web_contents()->GetURL();
158 if (IsReportableUrl(page_url)) 188 if (IsReportableUrl(page_url))
159 report_->set_page_url(page_url.spec()); 189 report_->set_page_url(page_url.spec());
160 190
161 GURL referrer_url; 191 GURL referrer_url;
162 NavigationEntry* nav_entry = web_contents()->GetController().GetActiveEntry(); 192 NavigationEntry* nav_entry = web_contents()->GetController().GetActiveEntry();
163 if (nav_entry) { 193 if (nav_entry) {
164 referrer_url = nav_entry->GetReferrer().url; 194 referrer_url = nav_entry->GetReferrer().url;
165 if (IsReportableUrl(referrer_url)) { 195 if (IsReportableUrl(referrer_url)) {
(...skipping 26 matching lines...) Expand all
192 // Set the previous redirect url as the parent of the next one 222 // Set the previous redirect url as the parent of the next one
193 for (size_t i = 0; i < resource_.redirect_urls.size(); ++i) { 223 for (size_t i = 0; i < resource_.redirect_urls.size(); ++i) {
194 AddUrl(resource_.redirect_urls[i], parent_url, std::string(), NULL); 224 AddUrl(resource_.redirect_urls[i], parent_url, std::string(), NULL);
195 parent_url = resource_.redirect_urls[i]; 225 parent_url = resource_.redirect_urls[i];
196 } 226 }
197 227
198 // Add the referrer url. 228 // Add the referrer url.
199 if (nav_entry && !referrer_url.is_empty()) 229 if (nav_entry && !referrer_url.is_empty())
200 AddUrl(referrer_url, GURL(), std::string(), NULL); 230 AddUrl(referrer_url, GURL(), std::string(), NULL);
201 231
232 // TODO(jialiul): figure out if we want to distinguish different threat types.
Nathan Parker 2015/11/03 20:51:57 Which threat types are you referring to here? Som
Jialiu Lin 2015/11/04 21:32:25 Oops, forgot to remove this TODO statement. The cu
202 // Get URLs of frames, scripts etc from the DOM. 233 // Get URLs of frames, scripts etc from the DOM.
203 // OnReceivedThreatDOMDetails will be called when the renderer replies. 234 // OnReceivedThreatDOMDetails will be called when the renderer replies.
204 content::RenderViewHost* view = web_contents()->GetRenderViewHost(); 235 content::RenderViewHost* view = web_contents()->GetRenderViewHost();
205 view->Send(new SafeBrowsingMsg_GetMalwareDOMDetails(view->GetRoutingID())); 236 view->Send(new SafeBrowsingMsg_GetThreatDOMDetails(view->GetRoutingID()));
206 } 237 }
207 238
208 // When the renderer is done, this is called. 239 // When the renderer is done, this is called.
209 void ThreatDetails::OnReceivedThreatDOMDetails( 240 void ThreatDetails::OnReceivedThreatDOMDetails(
210 const std::vector<SafeBrowsingHostMsg_MalwareDOMDetails_Node>& params) { 241 const std::vector<SafeBrowsingHostMsg_ThreatDOMDetails_Node>& params) {
211 // Schedule this in IO thread, so it doesn't conflict with future users 242 // Schedule this in IO thread, so it doesn't conflict with future users
212 // of our data structures (eg GetSerializedReport). 243 // of our data structures (eg GetSerializedReport).
213 BrowserThread::PostTask( 244 BrowserThread::PostTask(
214 BrowserThread::IO, FROM_HERE, 245 BrowserThread::IO, FROM_HERE,
215 base::Bind(&ThreatDetails::AddDOMDetails, this, params)); 246 base::Bind(&ThreatDetails::AddDOMDetails, this, params));
216 } 247 }
217 248
218 void ThreatDetails::AddDOMDetails( 249 void ThreatDetails::AddDOMDetails(
219 const std::vector<SafeBrowsingHostMsg_MalwareDOMDetails_Node>& params) { 250 const std::vector<SafeBrowsingHostMsg_ThreatDOMDetails_Node>& params) {
220 DCHECK_CURRENTLY_ON(BrowserThread::IO); 251 DCHECK_CURRENTLY_ON(BrowserThread::IO);
221 DVLOG(1) << "Nodes from the DOM: " << params.size(); 252 DVLOG(1) << "Nodes from the DOM: " << params.size();
222 253
223 // If we have already started getting redirects from history service, 254 // If we have already started getting redirects from history service,
224 // don't modify state, otherwise will invalidate the iterators. 255 // don't modify state, otherwise will invalidate the iterators.
225 if (redirects_collector_->HasStarted()) 256 if (redirects_collector_->HasStarted())
226 return; 257 return;
227 258
228 // If we have already started collecting data from the HTTP cache, don't 259 // If we have already started collecting data from the HTTP cache, don't
229 // modify our state. 260 // modify our state.
230 if (cache_collector_->HasStarted()) 261 if (cache_collector_->HasStarted())
231 return; 262 return;
232 263
233 // Add the urls from the DOM to |resources_|. The renderer could be 264 // Add the urls from the DOM to |resources_|. The renderer could be
234 // sending bogus messages, so limit the number of nodes we accept. 265 // sending bogus messages, so limit the number of nodes we accept.
235 for (size_t i = 0; i < params.size() && i < kMaxDomNodes; ++i) { 266 for (size_t i = 0; i < params.size() && i < kMaxDomNodes; ++i) {
236 SafeBrowsingHostMsg_MalwareDOMDetails_Node node = params[i]; 267 SafeBrowsingHostMsg_ThreatDOMDetails_Node node = params[i];
237 DVLOG(1) << node.url << ", " << node.tag_name << ", " << node.parent; 268 DVLOG(1) << node.url << ", " << node.tag_name << ", " << node.parent;
238 AddUrl(node.url, node.parent, node.tag_name, &(node.children)); 269 AddUrl(node.url, node.parent, node.tag_name, &(node.children));
239 } 270 }
240 } 271 }
241 272
242 // Called from the SB Service on the IO thread, after the user has 273 // Called from the SB Service on the IO thread, after the user has
243 // closed the tab, or clicked proceed or goback. Since the user needs 274 // closed the tab, or clicked proceed or goback. Since the user needs
244 // to take an action, we expect this to be called after 275 // to take an action, we expect this to be called after
245 // OnReceivedThreatDOMDetails in most cases. If not, we don't include 276 // OnReceivedThreatDOMDetails in most cases. If not, we don't include
246 // the DOM data in our report. 277 // the DOM data in our report.
(...skipping 30 matching lines...) Expand all
277 for (size_t i = 0; i < urls.size() - 1; ++i) { 308 for (size_t i = 0; i < urls.size() - 1; ++i) {
278 AddUrl(urls[i], urls[i + 1], std::string(), NULL); 309 AddUrl(urls[i], urls[i + 1], std::string(), NULL);
279 } 310 }
280 } 311 }
281 312
282 void ThreatDetails::OnCacheCollectionReady() { 313 void ThreatDetails::OnCacheCollectionReady() {
283 DVLOG(1) << "OnCacheCollectionReady."; 314 DVLOG(1) << "OnCacheCollectionReady.";
284 // Add all the urls in our |resources_| maps to the |report_| protocol buffer. 315 // Add all the urls in our |resources_| maps to the |report_| protocol buffer.
285 for (safe_browsing::ResourceMap::const_iterator it = resources_.begin(); 316 for (safe_browsing::ResourceMap::const_iterator it = resources_.begin();
286 it != resources_.end(); ++it) { 317 it != resources_.end(); ++it) {
287 ClientMalwareReportRequest::Resource* pb_resource = 318 ClientSafeBrowsingReportRequest::Resource* pb_resource =
288 report_->add_resources(); 319 report_->add_resources();
289 pb_resource->CopyFrom(*(it->second)); 320 pb_resource->CopyFrom(*(it->second));
290 const GURL url(pb_resource->url()); 321 const GURL url(pb_resource->url());
291 if (url.SchemeIs("https")) { 322 if (url.SchemeIs("https")) {
292 // Don't report headers of HTTPS requests since they may contain private 323 // Don't report headers of HTTPS requests since they may contain private
293 // cookies. We still retain the full URL. 324 // cookies. We still retain the full URL.
294 DVLOG(1) << "Clearing out HTTPS resource: " << pb_resource->url(); 325 DVLOG(1) << "Clearing out HTTPS resource: " << pb_resource->url();
295 pb_resource->clear_request(); 326 pb_resource->clear_request();
296 pb_resource->clear_response(); 327 pb_resource->clear_response();
297 // Keep id, parent_id, child_ids, and tag_name. 328 // Keep id, parent_id, child_ids, and tag_name.
298 } 329 }
299 } 330 }
300 report_->set_did_proceed(did_proceed_); 331 report_->set_did_proceed(did_proceed_);
301 // Only sets repeat_visit if num_visits_ >= 0. 332 // Only sets repeat_visit if num_visits_ >= 0.
302 if (num_visits_ >= 0) { 333 if (num_visits_ >= 0) {
303 report_->set_repeat_visit(num_visits_ > 0); 334 report_->set_repeat_visit(num_visits_ > 0);
304 } 335 }
305 report_->set_complete(cache_result_); 336 report_->set_complete(cache_result_);
306 337
307 // Send the report, using the SafeBrowsingService. 338 // Send the report, using the SafeBrowsingService.
308 std::string serialized; 339 std::string serialized;
309 if (!report_->SerializeToString(&serialized)) { 340 if (!report_->SerializeToString(&serialized)) {
310 DLOG(ERROR) << "Unable to serialize the malware report."; 341 DLOG(ERROR) << "Unable to serialize the threat report.";
311 return; 342 return;
312 } 343 }
313
314 ui_manager_->SendSerializedThreatDetails(serialized); 344 ui_manager_->SendSerializedThreatDetails(serialized);
315 } 345 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698