OLD | NEW |
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 #include "chrome/browser/extensions/api/downloads/downloads_api.h" | 5 #include "chrome/browser/extensions/api/downloads/downloads_api.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <cctype> | 8 #include <cctype> |
9 #include <iterator> | 9 #include <iterator> |
10 #include <set> | 10 #include <set> |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
57 #include "content/public/browser/resource_context.h" | 57 #include "content/public/browser/resource_context.h" |
58 #include "content/public/browser/resource_dispatcher_host.h" | 58 #include "content/public/browser/resource_dispatcher_host.h" |
59 #include "content/public/browser/web_contents.h" | 59 #include "content/public/browser/web_contents.h" |
60 #include "content/public/browser/web_contents_view.h" | 60 #include "content/public/browser/web_contents_view.h" |
61 #include "net/base/load_flags.h" | 61 #include "net/base/load_flags.h" |
62 #include "net/http/http_util.h" | 62 #include "net/http/http_util.h" |
63 #include "net/url_request/url_request.h" | 63 #include "net/url_request/url_request.h" |
64 #include "third_party/skia/include/core/SkBitmap.h" | 64 #include "third_party/skia/include/core/SkBitmap.h" |
65 #include "ui/webui/web_ui_util.h" | 65 #include "ui/webui/web_ui_util.h" |
66 | 66 |
| 67 namespace events = extensions::event_names; |
| 68 |
67 using content::BrowserContext; | 69 using content::BrowserContext; |
68 using content::BrowserThread; | 70 using content::BrowserThread; |
69 using content::DownloadId; | 71 using content::DownloadId; |
70 using content::DownloadItem; | 72 using content::DownloadItem; |
71 using content::DownloadManager; | 73 using content::DownloadManager; |
72 | 74 |
73 namespace download_extension_errors { | 75 namespace download_extension_errors { |
74 | 76 |
75 // Error messages | 77 // Error messages |
76 const char kGenericError[] = "I'm afraid I can't do that"; | 78 const char kGenericError[] = "I'm afraid I can't do that"; |
(...skipping 439 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
516 } | 518 } |
517 | 519 |
518 class ExtensionDownloadsEventRouterData : public base::SupportsUserData::Data { | 520 class ExtensionDownloadsEventRouterData : public base::SupportsUserData::Data { |
519 public: | 521 public: |
520 static ExtensionDownloadsEventRouterData* Get(DownloadItem* download_item) { | 522 static ExtensionDownloadsEventRouterData* Get(DownloadItem* download_item) { |
521 base::SupportsUserData::Data* data = download_item->GetUserData(kKey); | 523 base::SupportsUserData::Data* data = download_item->GetUserData(kKey); |
522 return (data == NULL) ? NULL : | 524 return (data == NULL) ? NULL : |
523 static_cast<ExtensionDownloadsEventRouterData*>(data); | 525 static_cast<ExtensionDownloadsEventRouterData*>(data); |
524 } | 526 } |
525 | 527 |
| 528 static void Remove(DownloadItem* download_item) { |
| 529 download_item->RemoveUserData(kKey); |
| 530 } |
| 531 |
526 explicit ExtensionDownloadsEventRouterData( | 532 explicit ExtensionDownloadsEventRouterData( |
527 DownloadItem* download_item, | 533 DownloadItem* download_item, |
528 scoped_ptr<base::DictionaryValue> json_item) | 534 scoped_ptr<base::DictionaryValue> json_item) |
529 : updated_(0), | 535 : updated_(0), |
530 changed_fired_(0), | 536 changed_fired_(0), |
531 json_(json_item.Pass()), | 537 json_(json_item.Pass()), |
532 determined_conflict_action_( | 538 determined_conflict_action_( |
533 extensions::api::downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY) { | 539 extensions::api::downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY) { |
534 download_item->SetUserData(kKey, this); | 540 download_item->SetUserData(kKey, this); |
535 } | 541 } |
(...skipping 656 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1192 } | 1198 } |
1193 | 1199 |
1194 ExtensionDownloadsEventRouter::ExtensionDownloadsEventRouter( | 1200 ExtensionDownloadsEventRouter::ExtensionDownloadsEventRouter( |
1195 Profile* profile, | 1201 Profile* profile, |
1196 DownloadManager* manager) | 1202 DownloadManager* manager) |
1197 : profile_(profile), | 1203 : profile_(profile), |
1198 ALLOW_THIS_IN_INITIALIZER_LIST(notifier_(manager, this)) { | 1204 ALLOW_THIS_IN_INITIALIZER_LIST(notifier_(manager, this)) { |
1199 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1205 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1200 DCHECK(profile_); | 1206 DCHECK(profile_); |
1201 extensions::EventRouter* router = extensions::ExtensionSystem::Get(profile_)-> | 1207 extensions::EventRouter* router = extensions::ExtensionSystem::Get(profile_)-> |
1202 event_router(); | 1208 event_router(); |
1203 if (router) | 1209 if (router) |
1204 router->RegisterObserver( | 1210 router->RegisterObserver(this, events::kOnDownloadDeterminingFilename); |
1205 this, extensions::event_names::kOnDownloadDeterminingFilename); | |
1206 } | 1211 } |
1207 | 1212 |
1208 ExtensionDownloadsEventRouter::~ExtensionDownloadsEventRouter() { | 1213 ExtensionDownloadsEventRouter::~ExtensionDownloadsEventRouter() { |
1209 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1214 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1210 extensions::EventRouter* router = extensions::ExtensionSystem::Get(profile_)-> | 1215 extensions::EventRouter* router = extensions::ExtensionSystem::Get(profile_)-> |
1211 event_router(); | 1216 event_router(); |
1212 if (router) | 1217 if (router) |
1213 router->UnregisterObserver(this); | 1218 router->UnregisterObserver(this); |
1214 } | 1219 } |
1215 | 1220 |
1216 // The method by which extensions hook into the filename determination process | 1221 // The method by which extensions hook into the filename determination process |
1217 // is based on the method by which the omnibox API allows extensions to hook | 1222 // is based on the method by which the omnibox API allows extensions to hook |
1218 // into the omnibox autocompletion process. Extensions that wish to play a part | 1223 // into the omnibox autocompletion process. Extensions that wish to play a part |
1219 // in the filename determination process call | 1224 // in the filename determination process call |
1220 // chrome.downloads.onDeterminingFilename.addListener, which adds an | 1225 // chrome.downloads.onDeterminingFilename.addListener, which adds an |
1221 // EventListener object to ExtensionEventRouter::listeners(). | 1226 // EventListener object to ExtensionEventRouter::listeners(). |
(...skipping 17 matching lines...) Expand all Loading... |
1239 // then the extension that was last installed wins. | 1244 // then the extension that was last installed wins. |
1240 | 1245 |
1241 void ExtensionDownloadsEventRouter::OnDeterminingFilename( | 1246 void ExtensionDownloadsEventRouter::OnDeterminingFilename( |
1242 DownloadItem* item, | 1247 DownloadItem* item, |
1243 const base::FilePath& suggested_path, | 1248 const base::FilePath& suggested_path, |
1244 const base::Closure& no_change, | 1249 const base::Closure& no_change, |
1245 const FilenameChangedCallback& change) { | 1250 const FilenameChangedCallback& change) { |
1246 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1251 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1247 ExtensionDownloadsEventRouterData* data = | 1252 ExtensionDownloadsEventRouterData* data = |
1248 ExtensionDownloadsEventRouterData::Get(item); | 1253 ExtensionDownloadsEventRouterData::Get(item); |
| 1254 if (!data) { |
| 1255 no_change.Run(); |
| 1256 return; |
| 1257 } |
1249 data->ClearPendingDeterminers(); | 1258 data->ClearPendingDeterminers(); |
1250 data->set_filename_change_callbacks(no_change, change); | 1259 data->set_filename_change_callbacks(no_change, change); |
1251 bool any_determiners = false; | 1260 bool any_determiners = false; |
1252 base::DictionaryValue* json = DownloadItemToJSON( | 1261 base::DictionaryValue* json = DownloadItemToJSON( |
1253 item, profile_->IsOffTheRecord()).release(); | 1262 item, profile_->IsOffTheRecord()).release(); |
1254 json->SetString(kFilenameKey, suggested_path.LossyDisplayName()); | 1263 json->SetString(kFilenameKey, suggested_path.LossyDisplayName()); |
1255 DispatchEvent(extensions::event_names::kOnDownloadDeterminingFilename, | 1264 DispatchEvent(events::kOnDownloadDeterminingFilename, |
1256 false, | 1265 false, |
1257 base::Bind(&OnDeterminingFilenameWillDispatchCallback, | 1266 base::Bind(&OnDeterminingFilenameWillDispatchCallback, |
1258 &any_determiners, | 1267 &any_determiners, |
1259 data), | 1268 data), |
1260 json); | 1269 json); |
1261 if (!any_determiners) { | 1270 if (!any_determiners) { |
1262 data->ClearPendingDeterminers(); | 1271 data->ClearPendingDeterminers(); |
1263 no_change.Run(); | 1272 no_change.Run(); |
1264 } | 1273 } |
1265 } | 1274 } |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1306 // forever waiting for this ext_id to report. | 1315 // forever waiting for this ext_id to report. |
1307 *error = download_extension_errors::kInvalidFilenameError; | 1316 *error = download_extension_errors::kInvalidFilenameError; |
1308 return false; | 1317 return false; |
1309 } | 1318 } |
1310 return true; | 1319 return true; |
1311 } | 1320 } |
1312 | 1321 |
1313 void ExtensionDownloadsEventRouter::OnListenerRemoved( | 1322 void ExtensionDownloadsEventRouter::OnListenerRemoved( |
1314 const extensions::EventListenerInfo& details) { | 1323 const extensions::EventListenerInfo& details) { |
1315 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1324 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1316 if (details.event_name != | |
1317 extensions::event_names::kOnDownloadDeterminingFilename) | |
1318 return; | |
1319 DownloadManager* manager = notifier_.GetManager(); | 1325 DownloadManager* manager = notifier_.GetManager(); |
1320 if (!manager) | 1326 if (!manager) |
1321 return; | 1327 return; |
| 1328 bool determiner_removed = ( |
| 1329 details.event_name == events::kOnDownloadDeterminingFilename); |
| 1330 extensions::EventRouter* router = extensions::ExtensionSystem::Get(profile_)-> |
| 1331 event_router(); |
| 1332 bool any_listeners = |
| 1333 router->HasEventListener(events::kOnDownloadChanged) || |
| 1334 router->HasEventListener(events::kOnDownloadDeterminingFilename); |
| 1335 if (!determiner_removed && any_listeners) |
| 1336 return; |
1322 DownloadManager::DownloadVector items; | 1337 DownloadManager::DownloadVector items; |
1323 manager->GetAllDownloads(&items); | 1338 manager->GetAllDownloads(&items); |
1324 // Notify any items that may be waiting for callbacks from this | |
1325 // extension/determiner. | |
1326 for (DownloadManager::DownloadVector::const_iterator iter = | 1339 for (DownloadManager::DownloadVector::const_iterator iter = |
1327 items.begin(); | 1340 items.begin(); |
1328 iter != items.end(); ++iter) { | 1341 iter != items.end(); ++iter) { |
1329 ExtensionDownloadsEventRouterData* data = | 1342 ExtensionDownloadsEventRouterData* data = |
1330 ExtensionDownloadsEventRouterData::Get(*iter); | 1343 ExtensionDownloadsEventRouterData::Get(*iter); |
1331 // This will almost always be a no-op, however, it is possible for an | 1344 if (!data) |
1332 // extension renderer to be unloaded while a download item is waiting | 1345 continue; |
1333 // for a determiner. In that case, the download item should proceed. | 1346 if (determiner_removed) { |
1334 if (data) | 1347 // Notify any items that may be waiting for callbacks from this |
| 1348 // extension/determiner. This will almost always be a no-op, however, it |
| 1349 // is possible for an extension renderer to be unloaded while a download |
| 1350 // item is waiting for a determiner. In that case, the download item |
| 1351 // should proceed. |
1335 data->DeterminerRemoved(details.extension_id); | 1352 data->DeterminerRemoved(details.extension_id); |
| 1353 } |
| 1354 if (!any_listeners) { |
| 1355 ExtensionDownloadsEventRouterData::Remove(*iter); |
| 1356 } |
1336 } | 1357 } |
1337 } | 1358 } |
1338 | 1359 |
1339 // That's all the methods that have to do with filename determination. The rest | 1360 // That's all the methods that have to do with filename determination. The rest |
1340 // have to do with the other, less special events. | 1361 // have to do with the other, less special events. |
1341 | 1362 |
1342 void ExtensionDownloadsEventRouter::OnDownloadCreated( | 1363 void ExtensionDownloadsEventRouter::OnDownloadCreated( |
1343 DownloadManager* manager, DownloadItem* download_item) { | 1364 DownloadManager* manager, DownloadItem* download_item) { |
1344 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1365 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1345 if (download_item->IsTemporary()) | 1366 if (download_item->IsTemporary()) |
1346 return; | 1367 return; |
1347 | 1368 |
| 1369 extensions::EventRouter* router = extensions::ExtensionSystem::Get(profile_)-> |
| 1370 event_router(); |
| 1371 // Avoid allocating a bunch of memory in DownloadItemToJSON if it isn't going |
| 1372 // to be used. |
| 1373 if (!router || |
| 1374 (!router->HasEventListener(events::kOnDownloadCreated) && |
| 1375 !router->HasEventListener(events::kOnDownloadChanged) && |
| 1376 !router->HasEventListener(events::kOnDownloadDeterminingFilename))) { |
| 1377 return; |
| 1378 } |
1348 scoped_ptr<base::DictionaryValue> json_item( | 1379 scoped_ptr<base::DictionaryValue> json_item( |
1349 DownloadItemToJSON(download_item, profile_->IsOffTheRecord())); | 1380 DownloadItemToJSON(download_item, profile_->IsOffTheRecord())); |
1350 DispatchEvent(extensions::event_names::kOnDownloadCreated, | 1381 DispatchEvent(events::kOnDownloadCreated, |
1351 true, | 1382 true, |
1352 extensions::Event::WillDispatchCallback(), | 1383 extensions::Event::WillDispatchCallback(), |
1353 json_item->DeepCopy()); | 1384 json_item->DeepCopy()); |
1354 if (!ExtensionDownloadsEventRouterData::Get(download_item)) | 1385 if (!ExtensionDownloadsEventRouterData::Get(download_item) && |
| 1386 (router->HasEventListener(events::kOnDownloadChanged) || |
| 1387 router->HasEventListener(events::kOnDownloadDeterminingFilename))) { |
1355 new ExtensionDownloadsEventRouterData(download_item, json_item.Pass()); | 1388 new ExtensionDownloadsEventRouterData(download_item, json_item.Pass()); |
| 1389 } |
1356 } | 1390 } |
1357 | 1391 |
1358 void ExtensionDownloadsEventRouter::OnDownloadUpdated( | 1392 void ExtensionDownloadsEventRouter::OnDownloadUpdated( |
1359 DownloadManager* manager, DownloadItem* download_item) { | 1393 DownloadManager* manager, DownloadItem* download_item) { |
1360 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1394 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1361 if (download_item->IsTemporary()) | 1395 extensions::EventRouter* router = extensions::ExtensionSystem::Get(profile_)-> |
1362 return; | 1396 event_router(); |
1363 | |
1364 ExtensionDownloadsEventRouterData* data = | 1397 ExtensionDownloadsEventRouterData* data = |
1365 ExtensionDownloadsEventRouterData::Get(download_item); | 1398 ExtensionDownloadsEventRouterData::Get(download_item); |
| 1399 if (download_item->IsTemporary() || |
| 1400 !router->HasEventListener(events::kOnDownloadChanged)) { |
| 1401 return; |
| 1402 } |
1366 if (!data) { | 1403 if (!data) { |
1367 // The download_item probably transitioned from temporary to not temporary. | 1404 // The download_item probably transitioned from temporary to not temporary, |
1368 OnDownloadCreated(manager, download_item); | 1405 // or else an event listener was added. |
1369 return; | 1406 data = new ExtensionDownloadsEventRouterData( |
| 1407 download_item, |
| 1408 scoped_ptr<base::DictionaryValue>(new base::DictionaryValue())); |
1370 } | 1409 } |
1371 scoped_ptr<base::DictionaryValue> new_json(DownloadItemToJSON( | 1410 scoped_ptr<base::DictionaryValue> new_json(DownloadItemToJSON( |
1372 download_item, profile_->IsOffTheRecord())); | 1411 download_item, profile_->IsOffTheRecord())); |
1373 scoped_ptr<base::DictionaryValue> delta(new base::DictionaryValue()); | 1412 scoped_ptr<base::DictionaryValue> delta(new base::DictionaryValue()); |
1374 delta->SetInteger(kIdKey, download_item->GetId()); | 1413 delta->SetInteger(kIdKey, download_item->GetId()); |
1375 std::set<std::string> new_fields; | 1414 std::set<std::string> new_fields; |
1376 bool changed = false; | 1415 bool changed = false; |
1377 | 1416 |
1378 // For each field in the new json representation of the download_item except | 1417 // For each field in the new json representation of the download_item except |
1379 // the bytesReceived field, if the field has changed from the previous old | 1418 // the bytesReceived field, if the field has changed from the previous old |
(...skipping 22 matching lines...) Expand all Loading... |
1402 if (new_fields.find(iter.key()) == new_fields.end()) { | 1441 if (new_fields.find(iter.key()) == new_fields.end()) { |
1403 delta->Set(iter.key() + ".previous", iter.value().DeepCopy()); | 1442 delta->Set(iter.key() + ".previous", iter.value().DeepCopy()); |
1404 changed = true; | 1443 changed = true; |
1405 } | 1444 } |
1406 } | 1445 } |
1407 | 1446 |
1408 // Update the OnChangedStat and dispatch the event if something significant | 1447 // Update the OnChangedStat and dispatch the event if something significant |
1409 // changed. Replace the stored json with the new json. | 1448 // changed. Replace the stored json with the new json. |
1410 data->OnItemUpdated(); | 1449 data->OnItemUpdated(); |
1411 if (changed) { | 1450 if (changed) { |
1412 DispatchEvent(extensions::event_names::kOnDownloadChanged, | 1451 DispatchEvent(events::kOnDownloadChanged, |
1413 true, | 1452 true, |
1414 extensions::Event::WillDispatchCallback(), | 1453 extensions::Event::WillDispatchCallback(), |
1415 delta.release()); | 1454 delta.release()); |
1416 data->OnChangedFired(); | 1455 data->OnChangedFired(); |
1417 } | 1456 } |
1418 data->set_json(new_json.Pass()); | 1457 data->set_json(new_json.Pass()); |
1419 } | 1458 } |
1420 | 1459 |
1421 void ExtensionDownloadsEventRouter::OnDownloadRemoved( | 1460 void ExtensionDownloadsEventRouter::OnDownloadRemoved( |
1422 DownloadManager* manager, DownloadItem* download_item) { | 1461 DownloadManager* manager, DownloadItem* download_item) { |
1423 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1462 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1424 if (download_item->IsTemporary()) | 1463 if (download_item->IsTemporary()) |
1425 return; | 1464 return; |
1426 DispatchEvent(extensions::event_names::kOnDownloadErased, | 1465 DispatchEvent(events::kOnDownloadErased, |
1427 true, | 1466 true, |
1428 extensions::Event::WillDispatchCallback(), | 1467 extensions::Event::WillDispatchCallback(), |
1429 base::Value::CreateIntegerValue(download_item->GetId())); | 1468 base::Value::CreateIntegerValue(download_item->GetId())); |
1430 } | 1469 } |
1431 | 1470 |
1432 void ExtensionDownloadsEventRouter::DispatchEvent( | 1471 void ExtensionDownloadsEventRouter::DispatchEvent( |
1433 const char* event_name, | 1472 const char* event_name, |
1434 bool include_incognito, | 1473 bool include_incognito, |
1435 const extensions::Event::WillDispatchCallback& will_dispatch_callback, | 1474 const extensions::Event::WillDispatchCallback& will_dispatch_callback, |
1436 base::Value* arg) { | 1475 base::Value* arg) { |
(...skipping 19 matching lines...) Expand all Loading... |
1456 DownloadsNotificationSource notification_source; | 1495 DownloadsNotificationSource notification_source; |
1457 notification_source.event_name = event_name; | 1496 notification_source.event_name = event_name; |
1458 notification_source.profile = profile_; | 1497 notification_source.profile = profile_; |
1459 content::Source<DownloadsNotificationSource> content_source( | 1498 content::Source<DownloadsNotificationSource> content_source( |
1460 ¬ification_source); | 1499 ¬ification_source); |
1461 content::NotificationService::current()->Notify( | 1500 content::NotificationService::current()->Notify( |
1462 chrome::NOTIFICATION_EXTENSION_DOWNLOADS_EVENT, | 1501 chrome::NOTIFICATION_EXTENSION_DOWNLOADS_EVENT, |
1463 content_source, | 1502 content_source, |
1464 content::Details<std::string>(&json_args)); | 1503 content::Details<std::string>(&json_args)); |
1465 } | 1504 } |
OLD | NEW |