| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011 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/extensions/extension_downloads_api.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 #include <cctype> | |
| 9 #include <iterator> | |
| 10 #include <set> | |
| 11 #include <string> | |
| 12 | |
| 13 #include "base/bind.h" | |
| 14 #include "base/callback.h" | |
| 15 #include "base/json/json_writer.h" | |
| 16 #include "base/logging.h" | |
| 17 #include "base/metrics/histogram.h" | |
| 18 #include "base/stl_util.h" | |
| 19 #include "base/string16.h" | |
| 20 #include "base/string_util.h" | |
| 21 #include "base/stringprintf.h" | |
| 22 #include "base/values.h" | |
| 23 #include "chrome/browser/browser_process.h" | |
| 24 #include "chrome/browser/download/download_service.h" | |
| 25 #include "chrome/browser/download/download_service_factory.h" | |
| 26 #include "chrome/browser/download/download_util.h" | |
| 27 #include "chrome/browser/extensions/extension_downloads_api_constants.h" | |
| 28 #include "chrome/browser/extensions/extension_event_names.h" | |
| 29 #include "chrome/browser/extensions/extension_event_router.h" | |
| 30 #include "chrome/browser/icon_loader.h" | |
| 31 #include "chrome/browser/icon_manager.h" | |
| 32 #include "chrome/browser/renderer_host/chrome_render_message_filter.h" | |
| 33 #include "chrome/browser/ui/browser_list.h" | |
| 34 #include "content/browser/download/download_file_manager.h" | |
| 35 #include "content/browser/download/download_item.h" | |
| 36 #include "content/browser/download/download_types.h" | |
| 37 #include "content/browser/download/interrupt_reasons.h" | |
| 38 #include "content/browser/renderer_host/render_process_host.h" | |
| 39 #include "content/browser/renderer_host/render_view_host.h" | |
| 40 #include "content/browser/renderer_host/resource_dispatcher_host.h" | |
| 41 #include "net/http/http_util.h" | |
| 42 #include "net/url_request/url_request.h" | |
| 43 | |
| 44 using content::BrowserThread; | |
| 45 | |
| 46 namespace constants = extension_downloads_api_constants; | |
| 47 | |
| 48 bool DownloadsFunctionInterface::RunImplImpl( | |
| 49 DownloadsFunctionInterface* pimpl) { | |
| 50 CHECK(pimpl); | |
| 51 if (!pimpl->ParseArgs()) return false; | |
| 52 UMA_HISTOGRAM_ENUMERATION( | |
| 53 "Download.ApiFunctions", pimpl->function(), DOWNLOADS_FUNCTION_LAST); | |
| 54 pimpl->RunInternal(); | |
| 55 return true; | |
| 56 } | |
| 57 | |
| 58 SyncDownloadsFunction::SyncDownloadsFunction( | |
| 59 DownloadsFunctionInterface::DownloadsFunctionName function) | |
| 60 : function_(function) { | |
| 61 } | |
| 62 | |
| 63 SyncDownloadsFunction::~SyncDownloadsFunction() {} | |
| 64 | |
| 65 bool SyncDownloadsFunction::RunImpl() { | |
| 66 return DownloadsFunctionInterface::RunImplImpl(this); | |
| 67 } | |
| 68 | |
| 69 DownloadsFunctionInterface::DownloadsFunctionName | |
| 70 SyncDownloadsFunction::function() const { | |
| 71 return function_; | |
| 72 } | |
| 73 | |
| 74 AsyncDownloadsFunction::AsyncDownloadsFunction( | |
| 75 DownloadsFunctionInterface::DownloadsFunctionName function) | |
| 76 : function_(function) { | |
| 77 } | |
| 78 | |
| 79 AsyncDownloadsFunction::~AsyncDownloadsFunction() {} | |
| 80 | |
| 81 bool AsyncDownloadsFunction::RunImpl() { | |
| 82 return DownloadsFunctionInterface::RunImplImpl(this); | |
| 83 } | |
| 84 | |
| 85 DownloadsFunctionInterface::DownloadsFunctionName | |
| 86 AsyncDownloadsFunction::function() const { | |
| 87 return function_; | |
| 88 } | |
| 89 | |
| 90 DownloadsDownloadFunction::DownloadsDownloadFunction() | |
| 91 : AsyncDownloadsFunction(DOWNLOADS_FUNCTION_DOWNLOAD) { | |
| 92 } | |
| 93 | |
| 94 DownloadsDownloadFunction::~DownloadsDownloadFunction() {} | |
| 95 | |
| 96 DownloadsDownloadFunction::IOData::IOData() | |
| 97 : save_as(false), | |
| 98 extra_headers(NULL), | |
| 99 method("GET"), | |
| 100 rdh(NULL), | |
| 101 resource_context(NULL), | |
| 102 render_process_host_id(0), | |
| 103 render_view_host_routing_id(0) { | |
| 104 } | |
| 105 | |
| 106 DownloadsDownloadFunction::IOData::~IOData() {} | |
| 107 | |
| 108 bool DownloadsDownloadFunction::ParseArgs() { | |
| 109 base::DictionaryValue* options = NULL; | |
| 110 std::string url; | |
| 111 iodata_.reset(new IOData()); | |
| 112 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &options)); | |
| 113 EXTENSION_FUNCTION_VALIDATE(options->GetString(constants::kUrlKey, &url)); | |
| 114 iodata_->url = GURL(url); | |
| 115 if (!iodata_->url.is_valid()) { | |
| 116 error_ = constants::kInvalidURL; | |
| 117 return false; | |
| 118 } | |
| 119 if (options->HasKey(constants::kFilenameKey)) | |
| 120 EXTENSION_FUNCTION_VALIDATE(options->GetString( | |
| 121 constants::kFilenameKey, &iodata_->filename)); | |
| 122 // TODO(benjhayden): More robust validation of filename. | |
| 123 if (((iodata_->filename[0] == L'.') && (iodata_->filename[1] == L'.')) || | |
| 124 (iodata_->filename[0] == L'/')) { | |
| 125 error_ = constants::kGenericError; | |
| 126 return false; | |
| 127 } | |
| 128 if (options->HasKey(constants::kSaveAsKey)) | |
| 129 EXTENSION_FUNCTION_VALIDATE(options->GetBoolean( | |
| 130 constants::kSaveAsKey, &iodata_->save_as)); | |
| 131 if (options->HasKey(constants::kMethodKey)) | |
| 132 EXTENSION_FUNCTION_VALIDATE(options->GetString( | |
| 133 constants::kMethodKey, &iodata_->method)); | |
| 134 // It's ok to use a pointer to extra_headers without DeepCopy()ing because | |
| 135 // |args_| (which owns *extra_headers) is guaranteed to live as long as | |
| 136 // |this|. | |
| 137 if (options->HasKey(constants::kHeadersKey)) | |
| 138 EXTENSION_FUNCTION_VALIDATE(options->GetList( | |
| 139 constants::kHeadersKey, &iodata_->extra_headers)); | |
| 140 if (options->HasKey(constants::kBodyKey)) | |
| 141 EXTENSION_FUNCTION_VALIDATE(options->GetString( | |
| 142 constants::kBodyKey, &iodata_->post_body)); | |
| 143 if (iodata_->extra_headers != NULL) { | |
| 144 for (size_t index = 0; index < iodata_->extra_headers->GetSize(); ++index) { | |
| 145 base::DictionaryValue* header = NULL; | |
| 146 std::string name, value; | |
| 147 EXTENSION_FUNCTION_VALIDATE(iodata_->extra_headers->GetDictionary( | |
| 148 index, &header)); | |
| 149 EXTENSION_FUNCTION_VALIDATE(header->GetString( | |
| 150 constants::kHeaderNameKey, &name)); | |
| 151 EXTENSION_FUNCTION_VALIDATE(header->GetString( | |
| 152 constants::kHeaderValueKey, &value)); | |
| 153 if (!net::HttpUtil::IsSafeHeader(name)) { | |
| 154 error_ = constants::kGenericError; | |
| 155 return false; | |
| 156 } | |
| 157 } | |
| 158 } | |
| 159 iodata_->rdh = g_browser_process->resource_dispatcher_host(); | |
| 160 iodata_->resource_context = &profile()->GetResourceContext(); | |
| 161 iodata_->render_process_host_id = render_view_host()->process()->id(); | |
| 162 iodata_->render_view_host_routing_id = render_view_host()->routing_id(); | |
| 163 return true; | |
| 164 } | |
| 165 | |
| 166 void DownloadsDownloadFunction::RunInternal() { | |
| 167 VLOG(1) << __FUNCTION__ << " " << iodata_->url.spec(); | |
| 168 if (!BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind( | |
| 169 &DownloadsDownloadFunction::BeginDownloadOnIOThread, this))) { | |
| 170 error_ = constants::kGenericError; | |
| 171 SendResponse(error_.empty()); | |
| 172 } | |
| 173 } | |
| 174 | |
| 175 void DownloadsDownloadFunction::BeginDownloadOnIOThread() { | |
| 176 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 177 DVLOG(1) << __FUNCTION__ << " " << iodata_->url.spec(); | |
| 178 DownloadSaveInfo save_info; | |
| 179 // TODO(benjhayden) Ensure that this filename is interpreted as a path | |
| 180 // relative to the default downloads directory without allowing '..'. | |
| 181 save_info.suggested_name = iodata_->filename; | |
| 182 net::URLRequest* request = new net::URLRequest(iodata_->url, iodata_->rdh); | |
| 183 request->set_method(iodata_->method); | |
| 184 if (iodata_->extra_headers != NULL) { | |
| 185 for (size_t index = 0; index < iodata_->extra_headers->GetSize(); ++index) { | |
| 186 base::DictionaryValue* header = NULL; | |
| 187 std::string name, value; | |
| 188 CHECK(iodata_->extra_headers->GetDictionary(index, &header)); | |
| 189 CHECK(header->GetString("name", &name)); | |
| 190 CHECK(header->GetString("value", &value)); | |
| 191 request->SetExtraRequestHeaderByName(name, value, false/*overwrite*/); | |
| 192 } | |
| 193 } | |
| 194 if (!iodata_->post_body.empty()) { | |
| 195 request->AppendBytesToUpload(iodata_->post_body.data(), | |
| 196 iodata_->post_body.size()); | |
| 197 } | |
| 198 iodata_->rdh->BeginDownload( | |
| 199 request, | |
| 200 save_info, | |
| 201 iodata_->save_as, | |
| 202 base::Bind(&DownloadsDownloadFunction::OnStarted, this), | |
| 203 iodata_->render_process_host_id, | |
| 204 iodata_->render_view_host_routing_id, | |
| 205 *(iodata_->resource_context)); | |
| 206 iodata_.reset(); | |
| 207 } | |
| 208 | |
| 209 void DownloadsDownloadFunction::OnStarted(DownloadId dl_id, net::Error error) { | |
| 210 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 211 VLOG(1) << __FUNCTION__ << " " << dl_id << " " << error; | |
| 212 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( | |
| 213 &DownloadsDownloadFunction::RespondOnUIThread, this, | |
| 214 dl_id.local(), error)); | |
| 215 } | |
| 216 | |
| 217 void DownloadsDownloadFunction::RespondOnUIThread(int dl_id, net::Error error) { | |
| 218 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 219 VLOG(1) << __FUNCTION__; | |
| 220 if (dl_id >= 0) { | |
| 221 result_.reset(base::Value::CreateIntegerValue(dl_id)); | |
| 222 } else { | |
| 223 error_ = net::ErrorToString(error); | |
| 224 } | |
| 225 SendResponse(error_.empty()); | |
| 226 } | |
| 227 | |
| 228 DownloadsSearchFunction::DownloadsSearchFunction() | |
| 229 : SyncDownloadsFunction(DOWNLOADS_FUNCTION_SEARCH) { | |
| 230 } | |
| 231 | |
| 232 DownloadsSearchFunction::~DownloadsSearchFunction() {} | |
| 233 | |
| 234 bool DownloadsSearchFunction::ParseArgs() { | |
| 235 base::DictionaryValue* query_json = NULL; | |
| 236 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &query_json)); | |
| 237 error_ = constants::kNotImplemented; | |
| 238 return false; | |
| 239 } | |
| 240 | |
| 241 void DownloadsSearchFunction::RunInternal() { | |
| 242 NOTIMPLEMENTED(); | |
| 243 } | |
| 244 | |
| 245 DownloadsPauseFunction::DownloadsPauseFunction() | |
| 246 : SyncDownloadsFunction(DOWNLOADS_FUNCTION_PAUSE) { | |
| 247 } | |
| 248 | |
| 249 DownloadsPauseFunction::~DownloadsPauseFunction() {} | |
| 250 | |
| 251 bool DownloadsPauseFunction::ParseArgs() { | |
| 252 int dl_id = 0; | |
| 253 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &dl_id)); | |
| 254 VLOG(1) << __FUNCTION__ << " " << dl_id; | |
| 255 error_ = constants::kNotImplemented; | |
| 256 return false; | |
| 257 } | |
| 258 | |
| 259 void DownloadsPauseFunction::RunInternal() { | |
| 260 NOTIMPLEMENTED(); | |
| 261 } | |
| 262 | |
| 263 DownloadsResumeFunction::DownloadsResumeFunction() | |
| 264 : AsyncDownloadsFunction(DOWNLOADS_FUNCTION_RESUME) { | |
| 265 } | |
| 266 | |
| 267 DownloadsResumeFunction::~DownloadsResumeFunction() {} | |
| 268 | |
| 269 bool DownloadsResumeFunction::ParseArgs() { | |
| 270 int dl_id = 0; | |
| 271 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &dl_id)); | |
| 272 VLOG(1) << __FUNCTION__ << " " << dl_id; | |
| 273 error_ = constants::kNotImplemented; | |
| 274 return false; | |
| 275 } | |
| 276 | |
| 277 void DownloadsResumeFunction::RunInternal() { | |
| 278 NOTIMPLEMENTED(); | |
| 279 } | |
| 280 | |
| 281 DownloadsCancelFunction::DownloadsCancelFunction() | |
| 282 : AsyncDownloadsFunction(DOWNLOADS_FUNCTION_CANCEL) { | |
| 283 } | |
| 284 | |
| 285 DownloadsCancelFunction::~DownloadsCancelFunction() {} | |
| 286 | |
| 287 bool DownloadsCancelFunction::ParseArgs() { | |
| 288 int dl_id = 0; | |
| 289 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &dl_id)); | |
| 290 VLOG(1) << __FUNCTION__ << " " << dl_id; | |
| 291 error_ = constants::kNotImplemented; | |
| 292 return false; | |
| 293 } | |
| 294 | |
| 295 void DownloadsCancelFunction::RunInternal() { | |
| 296 NOTIMPLEMENTED(); | |
| 297 } | |
| 298 | |
| 299 DownloadsEraseFunction::DownloadsEraseFunction() | |
| 300 : AsyncDownloadsFunction(DOWNLOADS_FUNCTION_ERASE) { | |
| 301 } | |
| 302 | |
| 303 DownloadsEraseFunction::~DownloadsEraseFunction() {} | |
| 304 | |
| 305 bool DownloadsEraseFunction::ParseArgs() { | |
| 306 base::DictionaryValue* query_json = NULL; | |
| 307 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &query_json)); | |
| 308 error_ = constants::kNotImplemented; | |
| 309 return false; | |
| 310 } | |
| 311 | |
| 312 void DownloadsEraseFunction::RunInternal() { | |
| 313 NOTIMPLEMENTED(); | |
| 314 } | |
| 315 | |
| 316 DownloadsSetDestinationFunction::DownloadsSetDestinationFunction() | |
| 317 : AsyncDownloadsFunction(DOWNLOADS_FUNCTION_SET_DESTINATION) { | |
| 318 } | |
| 319 | |
| 320 DownloadsSetDestinationFunction::~DownloadsSetDestinationFunction() {} | |
| 321 | |
| 322 bool DownloadsSetDestinationFunction::ParseArgs() { | |
| 323 int dl_id = 0; | |
| 324 std::string path; | |
| 325 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &dl_id)); | |
| 326 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &path)); | |
| 327 VLOG(1) << __FUNCTION__ << " " << dl_id << " " << &path; | |
| 328 error_ = constants::kNotImplemented; | |
| 329 return false; | |
| 330 } | |
| 331 | |
| 332 void DownloadsSetDestinationFunction::RunInternal() { | |
| 333 NOTIMPLEMENTED(); | |
| 334 } | |
| 335 | |
| 336 DownloadsAcceptDangerFunction::DownloadsAcceptDangerFunction() | |
| 337 : AsyncDownloadsFunction(DOWNLOADS_FUNCTION_ACCEPT_DANGER) { | |
| 338 } | |
| 339 | |
| 340 DownloadsAcceptDangerFunction::~DownloadsAcceptDangerFunction() {} | |
| 341 | |
| 342 bool DownloadsAcceptDangerFunction::ParseArgs() { | |
| 343 int dl_id = 0; | |
| 344 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &dl_id)); | |
| 345 VLOG(1) << __FUNCTION__ << " " << dl_id; | |
| 346 error_ = constants::kNotImplemented; | |
| 347 return false; | |
| 348 } | |
| 349 | |
| 350 void DownloadsAcceptDangerFunction::RunInternal() { | |
| 351 NOTIMPLEMENTED(); | |
| 352 } | |
| 353 | |
| 354 DownloadsShowFunction::DownloadsShowFunction() | |
| 355 : AsyncDownloadsFunction(DOWNLOADS_FUNCTION_SHOW) { | |
| 356 } | |
| 357 | |
| 358 DownloadsShowFunction::~DownloadsShowFunction() {} | |
| 359 | |
| 360 bool DownloadsShowFunction::ParseArgs() { | |
| 361 int dl_id = 0; | |
| 362 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &dl_id)); | |
| 363 VLOG(1) << __FUNCTION__ << " " << dl_id; | |
| 364 error_ = constants::kNotImplemented; | |
| 365 return false; | |
| 366 } | |
| 367 | |
| 368 void DownloadsShowFunction::RunInternal() { | |
| 369 NOTIMPLEMENTED(); | |
| 370 } | |
| 371 | |
| 372 DownloadsDragFunction::DownloadsDragFunction() | |
| 373 : AsyncDownloadsFunction(DOWNLOADS_FUNCTION_DRAG) { | |
| 374 } | |
| 375 | |
| 376 DownloadsDragFunction::~DownloadsDragFunction() {} | |
| 377 | |
| 378 bool DownloadsDragFunction::ParseArgs() { | |
| 379 int dl_id = 0; | |
| 380 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &dl_id)); | |
| 381 VLOG(1) << __FUNCTION__ << " " << dl_id; | |
| 382 error_ = constants::kNotImplemented; | |
| 383 return false; | |
| 384 } | |
| 385 | |
| 386 void DownloadsDragFunction::RunInternal() { | |
| 387 NOTIMPLEMENTED(); | |
| 388 } | |
| 389 | |
| 390 namespace { | |
| 391 base::DictionaryValue* DownloadItemToJSON(DownloadItem* item) { | |
| 392 base::DictionaryValue* json = new base::DictionaryValue(); | |
| 393 json->SetInteger(constants::kIdKey, item->id()); | |
| 394 json->SetString(constants::kUrlKey, item->original_url().spec()); | |
| 395 json->SetString(constants::kFilenameKey, | |
| 396 item->full_path().LossyDisplayName()); | |
| 397 json->SetString(constants::kDangerKey, | |
| 398 constants::DangerString(item->GetDangerType())); | |
| 399 json->SetBoolean(constants::kDangerAcceptedKey, | |
| 400 item->safety_state() == DownloadItem::DANGEROUS_BUT_VALIDATED); | |
| 401 json->SetString(constants::kStateKey, | |
| 402 constants::StateString(item->state())); | |
| 403 json->SetBoolean(constants::kPausedKey, item->is_paused()); | |
| 404 json->SetString(constants::kMimeKey, item->mime_type()); | |
| 405 json->SetInteger(constants::kStartTimeKey, | |
| 406 (item->start_time() - base::Time::UnixEpoch()).InMilliseconds()); | |
| 407 json->SetInteger(constants::kBytesReceivedKey, item->received_bytes()); | |
| 408 json->SetInteger(constants::kTotalBytesKey, item->total_bytes()); | |
| 409 if (item->state() == DownloadItem::INTERRUPTED) | |
| 410 json->SetInteger(constants::kErrorKey, | |
| 411 static_cast<int>(item->last_reason())); | |
| 412 // TODO(benjhayden): Implement endTime and fileSize. | |
| 413 // json->SetInteger(constants::kEndTimeKey, -1); | |
| 414 json->SetInteger(constants::kFileSizeKey, item->total_bytes()); | |
| 415 return json; | |
| 416 } | |
| 417 } // anonymous namespace | |
| 418 | |
| 419 ExtensionDownloadsEventRouter::ExtensionDownloadsEventRouter( | |
| 420 Profile* profile) | |
| 421 : profile_(profile), | |
| 422 manager_( | |
| 423 profile ? | |
| 424 DownloadServiceFactory::GetForProfile(profile)->GetDownloadManager() : | |
| 425 NULL) { | |
| 426 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 427 DCHECK(profile_); | |
| 428 DCHECK(manager_); | |
| 429 manager_->AddObserver(this); | |
| 430 } | |
| 431 | |
| 432 ExtensionDownloadsEventRouter::~ExtensionDownloadsEventRouter() { | |
| 433 if (manager_ != NULL) | |
| 434 manager_->RemoveObserver(this); | |
| 435 } | |
| 436 | |
| 437 void ExtensionDownloadsEventRouter::ModelChanged() { | |
| 438 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 439 if (manager_ == NULL) | |
| 440 return; | |
| 441 DownloadManager::DownloadVector current_vec; | |
| 442 manager_->SearchDownloads(string16(), ¤t_vec); | |
| 443 DownloadIdSet current_set; | |
| 444 ItemMap current_map; | |
| 445 for (DownloadManager::DownloadVector::const_iterator iter = | |
| 446 current_vec.begin(); | |
| 447 iter != current_vec.end(); ++iter) { | |
| 448 DownloadItem* item = *iter; | |
| 449 int item_id = item->id(); | |
| 450 // TODO(benjhayden): Remove the following line when every item's id >= 0, | |
| 451 // which will allow firing onErased events for items from the history. | |
| 452 if (item_id < 0) continue; | |
| 453 DCHECK(current_map.find(item_id) == current_map.end()); | |
| 454 current_set.insert(item_id); | |
| 455 current_map[item_id] = item; | |
| 456 } | |
| 457 DownloadIdSet new_set; // current_set - downloads_; | |
| 458 DownloadIdSet erased_set; // downloads_ - current_set; | |
| 459 std::insert_iterator<DownloadIdSet> new_insertor(new_set, new_set.begin()); | |
| 460 std::insert_iterator<DownloadIdSet> erased_insertor( | |
| 461 erased_set, erased_set.begin()); | |
| 462 std::set_difference(current_set.begin(), current_set.end(), | |
| 463 downloads_.begin(), downloads_.end(), | |
| 464 new_insertor); | |
| 465 std::set_difference(downloads_.begin(), downloads_.end(), | |
| 466 current_set.begin(), current_set.end(), | |
| 467 erased_insertor); | |
| 468 for (DownloadIdSet::const_iterator iter = new_set.begin(); | |
| 469 iter != new_set.end(); ++iter) { | |
| 470 DispatchEvent(extension_event_names::kOnDownloadCreated, | |
| 471 DownloadItemToJSON(current_map[*iter])); | |
| 472 } | |
| 473 for (DownloadIdSet::const_iterator iter = erased_set.begin(); | |
| 474 iter != erased_set.end(); ++iter) { | |
| 475 DispatchEvent(extension_event_names::kOnDownloadErased, | |
| 476 base::Value::CreateIntegerValue(*iter)); | |
| 477 } | |
| 478 downloads_.swap(current_set); | |
| 479 } | |
| 480 | |
| 481 void ExtensionDownloadsEventRouter::ManagerGoingDown() { | |
| 482 manager_->RemoveObserver(this); | |
| 483 manager_ = NULL; | |
| 484 } | |
| 485 | |
| 486 void ExtensionDownloadsEventRouter::DispatchEvent( | |
| 487 const char* event_name, base::Value* arg) { | |
| 488 ListValue args; | |
| 489 args.Append(arg); | |
| 490 std::string json_args; | |
| 491 base::JSONWriter::Write(&args, false, &json_args); | |
| 492 profile_->GetExtensionEventRouter()->DispatchEventToRenderers( | |
| 493 event_name, | |
| 494 json_args, | |
| 495 profile_, | |
| 496 GURL()); | |
| 497 } | |
| OLD | NEW |