blob: 8e4657fb85bc80b39f210fccd1a64bfaa1d13477 [file] [log] [blame]
[email protected]21d7a4e302011-08-15 16:17:121// 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>
[email protected]8e3ae68c2011-09-16 22:15:478#include <cctype>
[email protected]370e9502011-09-14 19:31:449#include <iterator>
10#include <set>
[email protected]21d7a4e302011-08-15 16:17:1211#include <string>
12
[email protected]8e3ae68c2011-09-16 22:15:4713#include "base/bind.h"
14#include "base/callback.h"
[email protected]370e9502011-09-14 19:31:4415#include "base/json/json_writer.h"
[email protected]21d7a4e302011-08-15 16:17:1216#include "base/logging.h"
[email protected]8a9bc222011-08-24 18:21:0017#include "base/metrics/histogram.h"
[email protected]21d7a4e302011-08-15 16:17:1218#include "base/stl_util.h"
[email protected]8e3ae68c2011-09-16 22:15:4719#include "base/string16.h"
20#include "base/string_util.h"
21#include "base/stringprintf.h"
[email protected]21d7a4e302011-08-15 16:17:1222#include "base/values.h"
23#include "chrome/browser/browser_process.h"
[email protected]9bb54ee2011-10-12 17:43:3524#include "chrome/browser/download/download_service.h"
25#include "chrome/browser/download/download_service_factory.h"
[email protected]21d7a4e302011-08-15 16:17:1226#include "chrome/browser/download/download_util.h"
27#include "chrome/browser/extensions/extension_downloads_api_constants.h"
[email protected]370e9502011-09-14 19:31:4428#include "chrome/browser/extensions/extension_event_names.h"
29#include "chrome/browser/extensions/extension_event_router.h"
[email protected]21d7a4e302011-08-15 16:17:1230#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"
[email protected]71bf3f5e2011-08-15 21:05:2234#include "content/browser/download/download_file_manager.h"
35#include "content/browser/download/download_item.h"
[email protected]8e3ae68c2011-09-16 22:15:4736#include "content/browser/download/download_types.h"
[email protected]be76b7e2011-10-13 12:57:5737#include "content/browser/download/interrupt_reasons.h"
[email protected]8e3ae68c2011-09-16 22:15:4738#include "content/browser/renderer_host/render_process_host.h"
[email protected]21d7a4e302011-08-15 16:17:1239#include "content/browser/renderer_host/render_view_host.h"
40#include "content/browser/renderer_host/resource_dispatcher_host.h"
[email protected]8e3ae68c2011-09-16 22:15:4741#include "net/http/http_util.h"
42#include "net/url_request/url_request.h"
[email protected]21d7a4e302011-08-15 16:17:1243
[email protected]631bb742011-11-02 11:29:3944using content::BrowserThread;
45
[email protected]21d7a4e302011-08-15 16:17:1246namespace constants = extension_downloads_api_constants;
47
[email protected]8a9bc222011-08-24 18:21:0048bool 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
58SyncDownloadsFunction::SyncDownloadsFunction(
59 DownloadsFunctionInterface::DownloadsFunctionName function)
60 : function_(function) {
61}
62
63SyncDownloadsFunction::~SyncDownloadsFunction() {}
64
65bool SyncDownloadsFunction::RunImpl() {
66 return DownloadsFunctionInterface::RunImplImpl(this);
67}
68
69DownloadsFunctionInterface::DownloadsFunctionName
70SyncDownloadsFunction::function() const {
71 return function_;
72}
73
74AsyncDownloadsFunction::AsyncDownloadsFunction(
75 DownloadsFunctionInterface::DownloadsFunctionName function)
76 : function_(function) {
77}
78
79AsyncDownloadsFunction::~AsyncDownloadsFunction() {}
80
81bool AsyncDownloadsFunction::RunImpl() {
82 return DownloadsFunctionInterface::RunImplImpl(this);
83}
84
85DownloadsFunctionInterface::DownloadsFunctionName
86AsyncDownloadsFunction::function() const {
87 return function_;
88}
89
[email protected]21d7a4e302011-08-15 16:17:1290DownloadsDownloadFunction::DownloadsDownloadFunction()
[email protected]8e3ae68c2011-09-16 22:15:4791 : AsyncDownloadsFunction(DOWNLOADS_FUNCTION_DOWNLOAD) {
[email protected]21d7a4e302011-08-15 16:17:1292}
[email protected]8a9bc222011-08-24 18:21:0093
[email protected]21d7a4e302011-08-15 16:17:1294DownloadsDownloadFunction::~DownloadsDownloadFunction() {}
95
[email protected]8e3ae68c2011-09-16 22:15:4796DownloadsDownloadFunction::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
106DownloadsDownloadFunction::IOData::~IOData() {}
107
[email protected]8a9bc222011-08-24 18:21:00108bool DownloadsDownloadFunction::ParseArgs() {
[email protected]21d7a4e302011-08-15 16:17:12109 base::DictionaryValue* options = NULL;
[email protected]8e3ae68c2011-09-16 22:15:47110 std::string url;
111 iodata_.reset(new IOData());
[email protected]21d7a4e302011-08-15 16:17:12112 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &options));
[email protected]8e3ae68c2011-09-16 22:15:47113 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 }
[email protected]21d7a4e302011-08-15 16:17:12119 if (options->HasKey(constants::kFilenameKey))
120 EXTENSION_FUNCTION_VALIDATE(options->GetString(
[email protected]8e3ae68c2011-09-16 22:15:47121 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 }
[email protected]21d7a4e302011-08-15 16:17:12128 if (options->HasKey(constants::kSaveAsKey))
129 EXTENSION_FUNCTION_VALIDATE(options->GetBoolean(
[email protected]8e3ae68c2011-09-16 22:15:47130 constants::kSaveAsKey, &iodata_->save_as));
[email protected]21d7a4e302011-08-15 16:17:12131 if (options->HasKey(constants::kMethodKey))
132 EXTENSION_FUNCTION_VALIDATE(options->GetString(
[email protected]8e3ae68c2011-09-16 22:15:47133 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|.
[email protected]21d7a4e302011-08-15 16:17:12137 if (options->HasKey(constants::kHeadersKey))
[email protected]8e3ae68c2011-09-16 22:15:47138 EXTENSION_FUNCTION_VALIDATE(options->GetList(
139 constants::kHeadersKey, &iodata_->extra_headers));
[email protected]21d7a4e302011-08-15 16:17:12140 if (options->HasKey(constants::kBodyKey))
141 EXTENSION_FUNCTION_VALIDATE(options->GetString(
[email protected]8e3ae68c2011-09-16 22:15:47142 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;
[email protected]21d7a4e302011-08-15 16:17:12164}
165
[email protected]8a9bc222011-08-24 18:21:00166void DownloadsDownloadFunction::RunInternal() {
[email protected]8e3ae68c2011-09-16 22:15:47167 VLOG(1) << __FUNCTION__ << " " << iodata_->url.spec();
[email protected]53612e82011-10-18 18:00:36168 if (!BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
169 &DownloadsDownloadFunction::BeginDownloadOnIOThread, this))) {
[email protected]8e3ae68c2011-09-16 22:15:47170 error_ = constants::kGenericError;
171 SendResponse(error_.empty());
172 }
173}
174
175void 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
[email protected]eda58402011-09-21 19:32:02209void DownloadsDownloadFunction::OnStarted(DownloadId dl_id, net::Error error) {
[email protected]8e3ae68c2011-09-16 22:15:47210 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
211 VLOG(1) << __FUNCTION__ << " " << dl_id << " " << error;
[email protected]53612e82011-10-18 18:00:36212 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
213 &DownloadsDownloadFunction::RespondOnUIThread, this,
[email protected]eda58402011-09-21 19:32:02214 dl_id.local(), error));
[email protected]8e3ae68c2011-09-16 22:15:47215}
216
217void 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());
[email protected]8a9bc222011-08-24 18:21:00226}
227
228DownloadsSearchFunction::DownloadsSearchFunction()
229 : SyncDownloadsFunction(DOWNLOADS_FUNCTION_SEARCH) {
230}
231
[email protected]21d7a4e302011-08-15 16:17:12232DownloadsSearchFunction::~DownloadsSearchFunction() {}
233
[email protected]8a9bc222011-08-24 18:21:00234bool DownloadsSearchFunction::ParseArgs() {
[email protected]8e3ae68c2011-09-16 22:15:47235 base::DictionaryValue* query_json = NULL;
[email protected]21d7a4e302011-08-15 16:17:12236 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &query_json));
237 error_ = constants::kNotImplemented;
238 return false;
239}
240
[email protected]8a9bc222011-08-24 18:21:00241void DownloadsSearchFunction::RunInternal() {
242 NOTIMPLEMENTED();
243}
244
245DownloadsPauseFunction::DownloadsPauseFunction()
246 : SyncDownloadsFunction(DOWNLOADS_FUNCTION_PAUSE) {
247}
248
[email protected]21d7a4e302011-08-15 16:17:12249DownloadsPauseFunction::~DownloadsPauseFunction() {}
250
[email protected]8a9bc222011-08-24 18:21:00251bool DownloadsPauseFunction::ParseArgs() {
[email protected]21d7a4e302011-08-15 16:17:12252 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
[email protected]8a9bc222011-08-24 18:21:00259void DownloadsPauseFunction::RunInternal() {
260 NOTIMPLEMENTED();
261}
262
263DownloadsResumeFunction::DownloadsResumeFunction()
264 : AsyncDownloadsFunction(DOWNLOADS_FUNCTION_RESUME) {
265}
266
[email protected]21d7a4e302011-08-15 16:17:12267DownloadsResumeFunction::~DownloadsResumeFunction() {}
268
[email protected]8a9bc222011-08-24 18:21:00269bool DownloadsResumeFunction::ParseArgs() {
[email protected]21d7a4e302011-08-15 16:17:12270 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
[email protected]8a9bc222011-08-24 18:21:00277void DownloadsResumeFunction::RunInternal() {
278 NOTIMPLEMENTED();
279}
280
281DownloadsCancelFunction::DownloadsCancelFunction()
282 : AsyncDownloadsFunction(DOWNLOADS_FUNCTION_CANCEL) {
283}
284
[email protected]21d7a4e302011-08-15 16:17:12285DownloadsCancelFunction::~DownloadsCancelFunction() {}
286
[email protected]8a9bc222011-08-24 18:21:00287bool DownloadsCancelFunction::ParseArgs() {
[email protected]21d7a4e302011-08-15 16:17:12288 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
[email protected]8a9bc222011-08-24 18:21:00295void DownloadsCancelFunction::RunInternal() {
296 NOTIMPLEMENTED();
297}
298
299DownloadsEraseFunction::DownloadsEraseFunction()
300 : AsyncDownloadsFunction(DOWNLOADS_FUNCTION_ERASE) {
301}
302
[email protected]21d7a4e302011-08-15 16:17:12303DownloadsEraseFunction::~DownloadsEraseFunction() {}
304
[email protected]8a9bc222011-08-24 18:21:00305bool DownloadsEraseFunction::ParseArgs() {
[email protected]8e3ae68c2011-09-16 22:15:47306 base::DictionaryValue* query_json = NULL;
[email protected]21d7a4e302011-08-15 16:17:12307 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &query_json));
308 error_ = constants::kNotImplemented;
309 return false;
310}
311
[email protected]8a9bc222011-08-24 18:21:00312void DownloadsEraseFunction::RunInternal() {
313 NOTIMPLEMENTED();
314}
315
316DownloadsSetDestinationFunction::DownloadsSetDestinationFunction()
317 : AsyncDownloadsFunction(DOWNLOADS_FUNCTION_SET_DESTINATION) {
318}
319
[email protected]21d7a4e302011-08-15 16:17:12320DownloadsSetDestinationFunction::~DownloadsSetDestinationFunction() {}
321
[email protected]8a9bc222011-08-24 18:21:00322bool DownloadsSetDestinationFunction::ParseArgs() {
[email protected]21d7a4e302011-08-15 16:17:12323 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
[email protected]8a9bc222011-08-24 18:21:00332void DownloadsSetDestinationFunction::RunInternal() {
333 NOTIMPLEMENTED();
334}
335
336DownloadsAcceptDangerFunction::DownloadsAcceptDangerFunction()
337 : AsyncDownloadsFunction(DOWNLOADS_FUNCTION_ACCEPT_DANGER) {
338}
339
[email protected]21d7a4e302011-08-15 16:17:12340DownloadsAcceptDangerFunction::~DownloadsAcceptDangerFunction() {}
341
[email protected]8a9bc222011-08-24 18:21:00342bool DownloadsAcceptDangerFunction::ParseArgs() {
[email protected]21d7a4e302011-08-15 16:17:12343 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
[email protected]8a9bc222011-08-24 18:21:00350void DownloadsAcceptDangerFunction::RunInternal() {
351 NOTIMPLEMENTED();
352}
353
354DownloadsShowFunction::DownloadsShowFunction()
355 : AsyncDownloadsFunction(DOWNLOADS_FUNCTION_SHOW) {
356}
357
[email protected]21d7a4e302011-08-15 16:17:12358DownloadsShowFunction::~DownloadsShowFunction() {}
359
[email protected]8a9bc222011-08-24 18:21:00360bool DownloadsShowFunction::ParseArgs() {
[email protected]21d7a4e302011-08-15 16:17:12361 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
[email protected]8a9bc222011-08-24 18:21:00368void DownloadsShowFunction::RunInternal() {
369 NOTIMPLEMENTED();
370}
371
372DownloadsDragFunction::DownloadsDragFunction()
373 : AsyncDownloadsFunction(DOWNLOADS_FUNCTION_DRAG) {
374}
375
[email protected]21d7a4e302011-08-15 16:17:12376DownloadsDragFunction::~DownloadsDragFunction() {}
377
[email protected]8a9bc222011-08-24 18:21:00378bool DownloadsDragFunction::ParseArgs() {
[email protected]21d7a4e302011-08-15 16:17:12379 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}
[email protected]8a9bc222011-08-24 18:21:00385
386void DownloadsDragFunction::RunInternal() {
387 NOTIMPLEMENTED();
388}
[email protected]370e9502011-09-14 19:31:44389
390namespace {
391base::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,
[email protected]be76b7e2011-10-13 12:57:57411 static_cast<int>(item->last_reason()));
[email protected]370e9502011-09-14 19:31:44412 // 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
419ExtensionDownloadsEventRouter::ExtensionDownloadsEventRouter(
420 Profile* profile)
421 : profile_(profile),
[email protected]9bb54ee2011-10-12 17:43:35422 manager_(
423 profile ?
424 DownloadServiceFactory::GetForProfile(profile)->GetDownloadManager() :
425 NULL) {
[email protected]370e9502011-09-14 19:31:44426 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
427 DCHECK(profile_);
428 DCHECK(manager_);
429 manager_->AddObserver(this);
430}
431
432ExtensionDownloadsEventRouter::~ExtensionDownloadsEventRouter() {
[email protected]fb4f8d902011-09-16 06:07:08433 if (manager_ != NULL)
434 manager_->RemoveObserver(this);
[email protected]370e9502011-09-14 19:31:44435}
436
437void ExtensionDownloadsEventRouter::ModelChanged() {
438 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]fb4f8d902011-09-16 06:07:08439 if (manager_ == NULL)
440 return;
[email protected]370e9502011-09-14 19:31:44441 DownloadManager::DownloadVector current_vec;
442 manager_->SearchDownloads(string16(), &current_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
481void ExtensionDownloadsEventRouter::ManagerGoingDown() {
[email protected]fb4f8d902011-09-16 06:07:08482 manager_->RemoveObserver(this);
[email protected]370e9502011-09-14 19:31:44483 manager_ = NULL;
484}
485
486void 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}