Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 MalwareDetails class. |
| 6 | 6 |
| 7 #include "chrome/browser/safe_browsing/malware_details.h" | 7 #include "chrome/browser/safe_browsing/malware_details.h" |
| 8 | 8 |
| 9 #include "base/callback.h" | |
| 9 #include "base/lazy_instance.h" | 10 #include "base/lazy_instance.h" |
| 11 #include "base/md5.h" | |
| 12 #include "chrome/browser/net/chrome_url_request_context.h" | |
| 13 #include "chrome/browser/profiles/profile.h" | |
| 10 #include "chrome/browser/safe_browsing/safe_browsing_service.h" | 14 #include "chrome/browser/safe_browsing/safe_browsing_service.h" |
| 11 #include "chrome/browser/safe_browsing/report.pb.h" | 15 #include "chrome/browser/safe_browsing/report.pb.h" |
| 16 #include "chrome/common/net/url_request_context_getter.h" | |
| 12 #include "chrome/common/render_messages.h" | 17 #include "chrome/common/render_messages.h" |
| 13 #include "chrome/common/render_messages_params.h" | 18 #include "chrome/common/render_messages_params.h" |
| 19 #include "net/base/io_buffer.h" | |
| 20 #include "net/disk_cache/disk_cache.h" | |
| 21 #include "net/http/http_cache.h" | |
| 22 #include "net/http/http_response_headers.h" | |
| 23 #include "net/http/http_response_info.h" | |
| 14 #include "content/browser/browser_thread.h" | 24 #include "content/browser/browser_thread.h" |
| 15 #include "content/browser/renderer_host/render_view_host.h" | 25 #include "content/browser/renderer_host/render_view_host.h" |
| 16 #include "content/browser/tab_contents/navigation_entry.h" | 26 #include "content/browser/tab_contents/navigation_entry.h" |
| 17 #include "content/browser/tab_contents/tab_contents.h" | 27 #include "content/browser/tab_contents/tab_contents.h" |
| 18 | 28 |
| 19 using safe_browsing::ClientMalwareReportRequest; | 29 using safe_browsing::ClientMalwareReportRequest; |
| 20 | 30 |
| 21 // Keep in sync with KMaxNodes in renderer/safe_browsing/malware_dom_details | 31 // Keep in sync with KMaxNodes in renderer/safe_browsing/malware_dom_details |
| 22 static const uint32 kMaxDomNodes = 500; | 32 static const uint32 kMaxDomNodes = 500; |
| 23 | 33 |
| 34 // Only send tiny files for now, a better strategy would use the size | |
| 35 // of the whole report and the user's bandwidth. | |
| 36 static const int kMaxBodySize = 1024; | |
| 37 | |
| 24 // static | 38 // static |
| 25 MalwareDetailsFactory* MalwareDetails::factory_ = NULL; | 39 MalwareDetailsFactory* MalwareDetails::factory_ = NULL; |
| 26 | 40 |
| 27 // The default MalwareDetailsFactory. Global, made a singleton so we | 41 // The default MalwareDetailsFactory. Global, made a singleton so we |
| 28 // don't leak it. | 42 // don't leak it. |
| 29 class MalwareDetailsFactoryImpl | 43 class MalwareDetailsFactoryImpl |
| 30 : public MalwareDetailsFactory { | 44 : public MalwareDetailsFactory { |
| 31 public: | 45 public: |
| 32 MalwareDetails* CreateMalwareDetails( | 46 MalwareDetails* CreateMalwareDetails( |
| 33 TabContents* tab_contents, | 47 TabContents* tab_contents, |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 57 if (!factory_) | 71 if (!factory_) |
| 58 factory_ = g_malware_details_factory_impl.Pointer(); | 72 factory_ = g_malware_details_factory_impl.Pointer(); |
| 59 return factory_->CreateMalwareDetails(tab_contents, resource); | 73 return factory_->CreateMalwareDetails(tab_contents, resource); |
| 60 } | 74 } |
| 61 | 75 |
| 62 // Create a MalwareDetails for the given tab. Runs in the UI thread. | 76 // Create a MalwareDetails for the given tab. Runs in the UI thread. |
| 63 MalwareDetails::MalwareDetails( | 77 MalwareDetails::MalwareDetails( |
| 64 TabContents* tab_contents, | 78 TabContents* tab_contents, |
| 65 const SafeBrowsingService::UnsafeResource resource) | 79 const SafeBrowsingService::UnsafeResource resource) |
| 66 : TabContentsObserver(tab_contents), | 80 : TabContentsObserver(tab_contents), |
| 67 resource_(resource) { | 81 resource_(resource), |
| 82 cache_state_(STATE_NONE), | |
| 83 ALLOW_THIS_IN_INITIALIZER_LIST( | |
| 84 cache_callback_(this, &MalwareDetails::CacheLoop)), | |
| 85 ALLOW_THIS_IN_INITIALIZER_LIST( | |
| 86 entry_callback_( | |
| 87 new net::CancelableCompletionCallback<MalwareDetails>( | |
| 88 this, &MalwareDetails::CacheLoop))) { | |
| 68 StartCollection(); | 89 StartCollection(); |
| 69 } | 90 } |
| 70 | 91 |
| 71 MalwareDetails::~MalwareDetails() {} | 92 MalwareDetails::~MalwareDetails() {} |
| 72 | 93 |
| 73 bool MalwareDetails::OnMessageReceived(const IPC::Message& message) { | 94 bool MalwareDetails::OnMessageReceived(const IPC::Message& message) { |
| 74 bool handled = true; | 95 bool handled = true; |
| 75 IPC_BEGIN_MESSAGE_MAP(MalwareDetails, message) | 96 IPC_BEGIN_MESSAGE_MAP(MalwareDetails, message) |
| 76 IPC_MESSAGE_HANDLER(ViewHostMsg_MalwareDOMDetails, | 97 IPC_MESSAGE_HANDLER(ViewHostMsg_MalwareDOMDetails, |
| 77 OnReceivedMalwareDOMDetails) | 98 OnReceivedMalwareDOMDetails) |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 185 } | 206 } |
| 186 | 207 |
| 187 // Add the referrer url. | 208 // Add the referrer url. |
| 188 if (nav_entry && !referrer_url.is_empty()) { | 209 if (nav_entry && !referrer_url.is_empty()) { |
| 189 AddUrl(referrer_url, GURL(), "", NULL); | 210 AddUrl(referrer_url, GURL(), "", NULL); |
| 190 } | 211 } |
| 191 | 212 |
| 192 // Get URLs of frames, scripts etc from the DOM. | 213 // Get URLs of frames, scripts etc from the DOM. |
| 193 // OnReceivedMalwareDOMDetails will be called when the renderer replies. | 214 // OnReceivedMalwareDOMDetails will be called when the renderer replies. |
| 194 tab_contents()->render_view_host()->GetMalwareDOMDetails(); | 215 tab_contents()->render_view_host()->GetMalwareDOMDetails(); |
| 216 | |
| 217 // DoOpenCache will need this later. Must be called on the UI thread, so | |
| 218 // we do it now. | |
| 219 request_context_getter_ = tab_contents()->profile()->GetRequestContext(); | |
|
lzheng
2011/03/05 00:37:50
Might be better to put this in the constructor.
panayiotis
2011/03/29 18:14:55
Done.
| |
| 195 } | 220 } |
| 196 | 221 |
| 197 // When the renderer is done, this is called. | 222 // When the renderer is done, this is called. |
| 198 void MalwareDetails::OnReceivedMalwareDOMDetails( | 223 void MalwareDetails::OnReceivedMalwareDOMDetails( |
| 199 const ViewHostMsg_MalwareDOMDetails_Params& params) { | 224 const ViewHostMsg_MalwareDOMDetails_Params& params) { |
| 200 // Schedule this in IO thread, so it doesn't conflict with future users | 225 // Schedule this in IO thread, so it doesn't conflict with future users |
| 201 // of our data structures (eg GetSerializedReport). | 226 // of our data structures (eg GetSerializedReport). |
| 202 BrowserThread::PostTask( | 227 BrowserThread::PostTask( |
| 203 BrowserThread::IO, FROM_HERE, | 228 BrowserThread::IO, FROM_HERE, |
| 204 NewRunnableMethod( | 229 NewRunnableMethod( |
| 205 this, &MalwareDetails::AddDOMDetails, params)); | 230 this, &MalwareDetails::AddDOMDetails, params)); |
| 206 } | 231 } |
| 207 | 232 |
| 208 void MalwareDetails::AddDOMDetails( | 233 void MalwareDetails::AddDOMDetails( |
| 209 const ViewHostMsg_MalwareDOMDetails_Params& params) { | 234 const ViewHostMsg_MalwareDOMDetails_Params& params) { |
| 210 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 235 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 236 DVLOG(1) << "Nodes from the DOM: " << params.nodes.size(); | |
| 237 // If we have already started collecting data from the HTTP cache, don't | |
|
lzheng
2011/03/05 00:37:50
nit: add an empty line above.
panayiotis
2011/03/29 18:14:55
Done.
| |
| 238 // modify our state. | |
| 239 if (cache_state_ != STATE_NONE) | |
| 240 return; | |
| 241 | |
| 211 // Add the urls from the DOM to |resources_|. The renderer could be | 242 // Add the urls from the DOM to |resources_|. The renderer could be |
| 212 // sending bogus messages, so limit the number of nodes we accept. | 243 // sending bogus messages, so limit the number of nodes we accept. |
| 213 DVLOG(1) << "Nodes from the DOM: " << params.nodes.size(); | |
| 214 for (uint32 i = 0; i < params.nodes.size() && i < kMaxDomNodes; ++i) { | 244 for (uint32 i = 0; i < params.nodes.size() && i < kMaxDomNodes; ++i) { |
| 215 ViewHostMsg_MalwareDOMDetails_Node node = params.nodes[i]; | 245 ViewHostMsg_MalwareDOMDetails_Node node = params.nodes[i]; |
| 216 DVLOG(1) << node.url << ", " << node.tag_name << ", " << node.parent; | 246 DVLOG(1) << node.url << ", " << node.tag_name << ", " << node.parent; |
| 217 AddUrl(node.url, node.parent, node.tag_name, &(node.children)); | 247 AddUrl(node.url, node.parent, node.tag_name, &(node.children)); |
| 218 } | 248 } |
| 219 } | 249 } |
| 220 | 250 |
| 221 // Called from the SB Service on the IO thread, after the user has | 251 // Called from the SB Service on the IO thread, after the user has |
| 222 // closed the tab, or clicked proceed or goback. Since the user needs | 252 // closed the tab, or clicked proceed or goback. Since the user needs |
| 223 // to take an action, we expect this to be called after | 253 // to take an action, we expect this to be called after |
| 224 // OnReceivedMalwareDOMDetails in most cases. If not, we don't include | 254 // OnReceivedMalwareDOMDetails in most cases. If not, we don't include |
| 225 // the DOM data in our report. | 255 // the DOM data in our report. |
| 226 const std::string* MalwareDetails::GetSerializedReport() { | 256 void MalwareDetails::StartCacheCollection(MalwareDetailsCallback* callback) { |
| 227 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 257 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 228 // The |report_| protocol buffer is now generated: We add all the | 258 |
| 229 // urls in our |resources_| maps. | 259 // Start the data collection from the HTTP cache. |
| 260 DVLOG(1) << "Getting disk_cache data for all urls..."; | |
| 261 resources_it_ = resources_.begin(); | |
| 262 cache_state_ = STATE_OPEN_CACHE; | |
| 263 callback_ = callback; | |
| 264 | |
| 265 // Post a task in the message loop, so the callers don't need to | |
| 266 // check if we call their callback immediately. | |
| 267 BrowserThread::PostTask( | |
| 268 BrowserThread::IO, FROM_HERE, | |
| 269 NewRunnableMethod( | |
| 270 this, &MalwareDetails::CacheLoop, net::OK)); | |
| 271 } | |
| 272 | |
| 273 // The IO thread loop. Called once the DOM details are callected, | |
| 274 // and then is passed to all the cache lookups as a callback. | |
| 275 void MalwareDetails::CacheLoop(int result) { | |
| 276 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 277 DCHECK(cache_state_ != STATE_NONE); | |
| 278 | |
| 279 int rv = result; | |
| 280 do { | |
| 281 DVLOG(1) << "cache_state_:" << cache_state_; | |
| 282 CacheState state = cache_state_; | |
| 283 cache_state_ = STATE_NONE; | |
| 284 switch (state) { | |
| 285 case STATE_OPEN_CACHE: | |
| 286 rv = DoOpenCache(); | |
| 287 break; | |
| 288 case STATE_OPEN_CACHE_COMPLETE: | |
| 289 rv = DoOpenCacheComplete(rv); | |
| 290 break; | |
| 291 case STATE_OPEN_ENTRY: | |
| 292 rv = DoOpenEntry(); | |
| 293 break; | |
| 294 case STATE_OPEN_ENTRY_COMPLETE: | |
| 295 rv = DoOpenEntryComplete(rv); | |
| 296 break; | |
| 297 case STATE_READ_RESPONSE: | |
| 298 rv = DoReadResponse(); | |
| 299 break; | |
| 300 case STATE_READ_RESPONSE_COMPLETE: | |
| 301 rv = DoReadResponseComplete(rv); | |
| 302 break; | |
| 303 case STATE_READ_DATA: | |
| 304 rv = DoReadData(); | |
| 305 break; | |
| 306 case STATE_READ_DATA_COMPLETE: | |
| 307 rv = DoReadDataComplete(rv); | |
| 308 break; | |
| 309 default: | |
| 310 NOTREACHED() << "Bad state:" << state; | |
| 311 rv = net::ERR_FAILED; | |
| 312 break; | |
| 313 } | |
| 314 } while (rv != net::ERR_IO_PENDING && cache_state_ != STATE_NONE); | |
| 315 | |
| 316 if (rv != net::ERR_IO_PENDING) { | |
| 317 DVLOG(1) << "CacheIO done."; | |
| 318 DoCacheDone(rv); | |
| 319 } | |
| 320 } | |
| 321 | |
| 322 net::URLRequestContext* MalwareDetails::GetURLRequestContext() { | |
| 323 if (!request_context_getter_) { | |
| 324 DVLOG(1) << "Missing request context getter"; | |
| 325 return NULL; | |
| 326 } | |
| 327 return request_context_getter_->GetURLRequestContext(); | |
| 328 } | |
| 329 | |
| 330 int MalwareDetails::DoOpenCache() { | |
| 331 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 332 cache_state_ = STATE_OPEN_CACHE_COMPLETE; | |
| 333 | |
| 334 net::URLRequestContext* context = GetURLRequestContext(); | |
| 335 if (!context) { | |
| 336 LOG(ERROR) << "Could not get URLRequestContext"; | |
| 337 cache_state_ = STATE_NONE; | |
| 338 return net::ERR_FAILED; | |
| 339 } | |
| 340 | |
| 341 if (!context->http_transaction_factory()) { | |
| 342 DVLOG(1) << "Could not get HTTP transaction factory"; | |
| 343 cache_state_ = STATE_NONE; | |
| 344 return net::ERR_FAILED; | |
| 345 } | |
| 346 | |
| 347 net::HttpCache* http_cache = | |
| 348 context->http_transaction_factory()->GetCache(); | |
| 349 if (!http_cache) { | |
| 350 DVLOG(1) << "Could not get http cache"; | |
| 351 cache_state_ = STATE_NONE; | |
| 352 return net::ERR_FAILED; | |
| 353 } | |
| 354 | |
| 355 return http_cache->GetBackend(&cache_, &cache_callback_); | |
| 356 } | |
| 357 | |
| 358 int MalwareDetails::DoOpenCacheComplete(int result) { | |
| 359 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 360 cache_state_ = STATE_OPEN_ENTRY; | |
| 361 | |
| 362 if (result == net::ERR_FAILED || !cache_) { | |
| 363 LOG(ERROR) << "Could not get disk cache"; | |
| 364 cache_state_ = STATE_NONE; | |
| 365 return net::ERR_FAILED; | |
| 366 } | |
| 367 | |
| 368 return net::OK; | |
| 369 } | |
| 370 | |
| 371 int MalwareDetails::DoOpenEntry() { | |
| 372 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 373 cache_state_ = STATE_OPEN_ENTRY_COMPLETE; | |
| 374 | |
| 375 if (resources_it_ == resources_.end()) { | |
| 376 cache_state_ = STATE_NONE; | |
| 377 return net::OK; | |
| 378 } | |
| 379 | |
| 380 entry_ = NULL; // Reset the entry. | |
| 381 return cache_->OpenEntry(resources_it_->first, &entry_, &cache_callback_); | |
| 382 } | |
| 383 | |
| 384 int MalwareDetails::DoOpenEntryComplete(int rv) { | |
| 385 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 386 cache_state_ = STATE_READ_RESPONSE; | |
| 387 return net::OK; | |
| 388 } | |
| 389 | |
| 390 int MalwareDetails::DoReadResponse() { | |
| 391 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 392 cache_state_ = STATE_READ_RESPONSE_COMPLETE; | |
| 393 entry_callback_->AddRef(); | |
|
lzheng
2011/03/05 00:37:50
Since MalwareDetails is refcounted, while waiting
panayiotis
2011/03/29 18:14:55
I managed to not refcount this callback. But the c
| |
| 394 | |
| 395 if (!entry_) { // No entry in the cache for this url. | |
| 396 return net::OK; | |
| 397 } | |
| 398 | |
| 399 // net::HttpCache::kResponseInfoIndex = 0. | |
| 400 buf_len_ = entry_->GetDataSize(0); | |
| 401 if (!buf_len_) { | |
| 402 DVLOG(1) << "Empty response"; | |
| 403 return buf_len_; | |
| 404 } | |
| 405 | |
| 406 buf_ = new net::IOBuffer(buf_len_); | |
| 407 return entry_->ReadData(0, 0, buf_, buf_len_, entry_callback_); | |
| 408 } | |
| 409 | |
| 410 int MalwareDetails::DoReadResponseComplete(int result) { | |
| 411 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 412 cache_state_ = STATE_READ_DATA; | |
| 413 entry_callback_->Release(); | |
| 414 | |
| 415 if (!entry_ || !result || result != buf_len_) { | |
| 416 DVLOG(1) << "No entry"; | |
| 417 } else { | |
| 418 linked_ptr<safe_browsing::ClientMalwareReportRequest::Resource> | |
| 419 pb_resource = resources_it_->second; | |
| 420 net::HttpResponseInfo response; | |
| 421 bool truncated; | |
| 422 if (net::HttpCache::ParseResponseInfo(buf_->data(), buf_len_, &response, | |
| 423 &truncated)) { | |
| 424 if (!truncated) { | |
| 425 if (response.headers) { | |
| 426 safe_browsing::ClientMalwareReportRequest::HTTPResponse* pb_response = | |
| 427 pb_resource->mutable_response(); | |
| 428 pb_response->mutable_firstline()->set_code( | |
| 429 response.headers->response_code()); | |
| 430 void* iter = NULL; | |
| 431 std::string name, value; | |
| 432 while (response.headers->EnumerateHeaderLines(&iter, &name, &value)) { | |
| 433 // Strip any Set-Cookie headers. | |
| 434 if (LowerCaseEqualsASCII(name, "set-cookie")) { | |
| 435 continue; | |
| 436 } | |
| 437 safe_browsing::ClientMalwareReportRequest::HTTPHeader* pb_header = | |
| 438 pb_response->add_headers(); | |
| 439 pb_header->set_name(name); | |
| 440 pb_header->set_value(value); | |
| 441 } | |
| 442 } else { | |
| 443 DVLOG(1) << "Missing response headers."; | |
| 444 } | |
| 445 } else { | |
| 446 DVLOG(1) << "Response truncated"; | |
| 447 } | |
| 448 } else { | |
| 449 LOG(ERROR) << "Could not parse HTTP cache entry"; | |
| 450 } | |
| 451 } | |
| 452 | |
| 453 return net::OK; | |
| 454 } | |
| 455 | |
| 456 int MalwareDetails::DoReadData() { | |
| 457 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 458 cache_state_ = STATE_READ_DATA_COMPLETE; | |
| 459 entry_callback_->AddRef(); | |
| 460 | |
| 461 if (!entry_) { // No entry in the cache for this url. | |
| 462 return net::OK; | |
| 463 } | |
| 464 | |
| 465 // net::HttpCache::kResponseContentIndex = 1. | |
| 466 buf_len_ = entry_->GetDataSize(1); | |
| 467 if (!buf_len_) { | |
| 468 DVLOG(1) << "Empty data"; | |
| 469 return buf_len_; | |
| 470 } | |
| 471 | |
| 472 buf_ = new net::IOBuffer(buf_len_); | |
| 473 return entry_->ReadData(1, 0, buf_, buf_len_, entry_callback_); | |
| 474 } | |
| 475 | |
| 476 int MalwareDetails::DoReadDataComplete(int result) { | |
| 477 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 478 cache_state_ = STATE_OPEN_ENTRY; | |
| 479 entry_callback_->Release(); | |
| 480 | |
| 481 if (entry_ && result && result == buf_len_) { | |
| 482 linked_ptr<safe_browsing::ClientMalwareReportRequest::Resource> | |
| 483 pb_resource = resources_it_->second; | |
| 484 safe_browsing::ClientMalwareReportRequest::HTTPResponse* pb_response = | |
| 485 pb_resource->mutable_response(); | |
| 486 if (buf_len_ <= kMaxBodySize) { // Only send small bodies for now. | |
| 487 pb_response->set_body(buf_->data(), buf_len_); | |
| 488 } | |
| 489 pb_response->set_bodylength(buf_len_); | |
| 490 MD5Digest digest; | |
| 491 MD5Sum(buf_->data(), buf_len_, &digest); | |
| 492 pb_response->set_bodydigest(MD5DigestToBase16(digest)); | |
| 493 entry_->Close(); | |
| 494 } | |
| 495 | |
| 496 ++resources_it_; // Advance to the next entry. | |
| 497 return net::OK; | |
| 498 } | |
| 499 | |
| 500 void MalwareDetails::DoCacheDone(int result) { | |
| 501 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 502 // Add all the urls in our |resources_| maps to the |report_| protocol buffer. | |
| 230 for (ResourceMap::const_iterator it = resources_.begin(); | 503 for (ResourceMap::const_iterator it = resources_.begin(); |
| 231 it != resources_.end(); it++) { | 504 it != resources_.end(); it++) { |
| 232 ClientMalwareReportRequest::Resource* pb_resource = | 505 ClientMalwareReportRequest::Resource* pb_resource = |
| 233 report_->add_resources(); | 506 report_->add_resources(); |
| 234 pb_resource->CopyFrom(*(it->second)); | 507 pb_resource->CopyFrom(*(it->second)); |
| 235 } | 508 } |
| 236 | 509 report_->set_complete(result == net::OK); |
| 510 | |
| 511 callback_->Run(this); | |
| 512 } | |
| 513 | |
| 514 const std::string* MalwareDetails::GetSerializedReport() { | |
| 515 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 237 scoped_ptr<std::string> request_data(new std::string()); | 516 scoped_ptr<std::string> request_data(new std::string()); |
| 238 if (!report_->SerializeToString(request_data.get())) { | 517 if (!report_->SerializeToString(request_data.get())) { |
| 239 DLOG(ERROR) << "Unable to serialize the malware report."; | 518 DLOG(ERROR) << "Unable to serialize the malware report."; |
| 240 } | 519 } |
| 241 | 520 |
| 242 return request_data.release(); | 521 return request_data.release(); |
| 243 } | 522 } |
| OLD | NEW |