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

Side by Side Diff: chrome/browser/extensions/api/downloads/downloads_api.cc

Issue 9617010: Move chrome.downloads out of experimental to dev (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: comments Created 8 years, 6 months 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 | Annotate | Revision Log
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 #include "chrome/browser/download/download_extension_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>
11 #include <string> 11 #include <string>
12 12
13 #include "base/basictypes.h" 13 #include "base/basictypes.h"
14 #include "base/bind.h" 14 #include "base/bind.h"
15 #include "base/bind_helpers.h" 15 #include "base/bind_helpers.h"
(...skipping 12 matching lines...) Expand all
28 #include "chrome/browser/download/download_file_icon_extractor.h" 28 #include "chrome/browser/download/download_file_icon_extractor.h"
29 #include "chrome/browser/download/download_query.h" 29 #include "chrome/browser/download/download_query.h"
30 #include "chrome/browser/download/download_service.h" 30 #include "chrome/browser/download/download_service.h"
31 #include "chrome/browser/download/download_service_factory.h" 31 #include "chrome/browser/download/download_service_factory.h"
32 #include "chrome/browser/download/download_util.h" 32 #include "chrome/browser/download/download_util.h"
33 #include "chrome/browser/extensions/extension_event_names.h" 33 #include "chrome/browser/extensions/extension_event_names.h"
34 #include "chrome/browser/extensions/extension_event_router.h" 34 #include "chrome/browser/extensions/extension_event_router.h"
35 #include "chrome/browser/icon_loader.h" 35 #include "chrome/browser/icon_loader.h"
36 #include "chrome/browser/icon_manager.h" 36 #include "chrome/browser/icon_manager.h"
37 #include "chrome/browser/renderer_host/chrome_render_message_filter.h" 37 #include "chrome/browser/renderer_host/chrome_render_message_filter.h"
38 #include "chrome/browser/ui/browser_list.h" 38 #include "chrome/browser/ui/browser.h"
39 #include "chrome/browser/ui/webui/web_ui_util.h" 39 #include "chrome/browser/ui/webui/web_ui_util.h"
40 #include "chrome/common/extensions/api/downloads.h"
40 #include "content/public/browser/download_interrupt_reasons.h" 41 #include "content/public/browser/download_interrupt_reasons.h"
41 #include "content/public/browser/download_item.h" 42 #include "content/public/browser/download_item.h"
42 #include "content/public/browser/download_save_info.h" 43 #include "content/public/browser/download_save_info.h"
44 #include "content/public/browser/download_url_parameters.h"
43 #include "content/public/browser/render_process_host.h" 45 #include "content/public/browser/render_process_host.h"
44 #include "content/public/browser/render_view_host.h" 46 #include "content/public/browser/render_view_host.h"
45 #include "content/public/browser/resource_dispatcher_host.h" 47 #include "content/public/browser/resource_dispatcher_host.h"
46 #include "net/base/load_flags.h" 48 #include "net/base/load_flags.h"
47 #include "net/http/http_util.h" 49 #include "net/http/http_util.h"
48 #include "net/url_request/url_request.h" 50 #include "net/url_request/url_request.h"
49 51
50 using content::BrowserThread; 52 using content::BrowserThread;
51 using content::DownloadId; 53 using content::DownloadId;
52 using content::DownloadItem; 54 using content::DownloadItem;
53 using content::DownloadManager; 55 using content::DownloadManager;
56 using extensions::api::downloads::HeaderNameValuePair;
54 57
55 namespace download_extension_errors { 58 namespace download_extension_errors {
56 59
57 // Error messages 60 // Error messages
58 const char kGenericError[] = "I'm afraid I can't do that."; 61 const char kGenericError[] = "I'm afraid I can't do that.";
59 const char kIconNotFoundError[] = "Icon not found."; 62 const char kIconNotFoundError[] = "Icon not found.";
60 const char kInvalidDangerTypeError[] = "Invalid danger type"; 63 const char kInvalidDangerTypeError[] = "Invalid danger type";
61 const char kInvalidFilterError[] = "Invalid query filter"; 64 const char kInvalidFilterError[] = "Invalid query filter";
62 const char kInvalidOperationError[] = "Invalid operation."; 65 const char kInvalidOperationError[] = "Invalid operation.";
63 const char kInvalidOrderByError[] = "Invalid orderBy field"; 66 const char kInvalidOrderByError[] = "Invalid orderBy field";
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
109 const char kStateInProgress[] = "in_progress"; 112 const char kStateInProgress[] = "in_progress";
110 const char kStateInterrupted[] = "interrupted"; 113 const char kStateInterrupted[] = "interrupted";
111 const char kStateKey[] = "state"; 114 const char kStateKey[] = "state";
112 const char kTotalBytesKey[] = "totalBytes"; 115 const char kTotalBytesKey[] = "totalBytes";
113 const char kTotalBytesGreaterKey[] = "totalBytesGreater"; 116 const char kTotalBytesGreaterKey[] = "totalBytesGreater";
114 const char kTotalBytesLessKey[] = "totalBytesLess"; 117 const char kTotalBytesLessKey[] = "totalBytesLess";
115 const char kUrlKey[] = "url"; 118 const char kUrlKey[] = "url";
116 const char kUrlRegexKey[] = "urlRegex"; 119 const char kUrlRegexKey[] = "urlRegex";
117 120
118 // Note: Any change to the danger type strings, should be accompanied by a 121 // Note: Any change to the danger type strings, should be accompanied by a
119 // corresponding change to {experimental.}downloads.json. 122 // corresponding change to downloads.idl.
120 const char* kDangerStrings[] = { 123 const char* kDangerStrings[] = {
121 kDangerSafe, 124 kDangerSafe,
122 kDangerFile, 125 kDangerFile,
123 kDangerUrl, 126 kDangerUrl,
124 kDangerContent, 127 kDangerContent,
125 kDangerSafe, 128 kDangerSafe,
126 kDangerUncommon, 129 kDangerUncommon,
127 }; 130 };
128 COMPILE_ASSERT(arraysize(kDangerStrings) == content::DOWNLOAD_DANGER_TYPE_MAX, 131 COMPILE_ASSERT(arraysize(kDangerStrings) == content::DOWNLOAD_DANGER_TYPE_MAX,
129 download_danger_type_enum_changed); 132 download_danger_type_enum_changed);
130 133
131 // Note: Any change to the state strings, should be accompanied by a 134 // Note: Any change to the state strings, should be accompanied by a
132 // corresponding change to {experimental.}downloads.json. 135 // corresponding change to downloads.idl.
133 const char* kStateStrings[] = { 136 const char* kStateStrings[] = {
134 kStateInProgress, 137 kStateInProgress,
135 kStateComplete, 138 kStateComplete,
136 kStateInterrupted, 139 kStateInterrupted,
137 NULL, 140 NULL,
138 kStateInterrupted, 141 kStateInterrupted,
139 }; 142 };
140 COMPILE_ASSERT(arraysize(kStateStrings) == DownloadItem::MAX_DOWNLOAD_STATE, 143 COMPILE_ASSERT(arraysize(kStateStrings) == DownloadItem::MAX_DOWNLOAD_STATE,
141 download_item_state_enum_changed); 144 download_item_state_enum_changed);
142 145
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after
314 bool include_incognito, 317 bool include_incognito,
315 DownloadManager** manager, DownloadManager** incognito_manager) { 318 DownloadManager** manager, DownloadManager** incognito_manager) {
316 *manager = DownloadServiceFactory::GetForProfile(profile)-> 319 *manager = DownloadServiceFactory::GetForProfile(profile)->
317 GetDownloadManager(); 320 GetDownloadManager();
318 *incognito_manager = NULL; 321 *incognito_manager = NULL;
319 if (include_incognito && profile->HasOffTheRecordProfile()) 322 if (include_incognito && profile->HasOffTheRecordProfile())
320 *incognito_manager = DownloadServiceFactory::GetForProfile(profile-> 323 *incognito_manager = DownloadServiceFactory::GetForProfile(profile->
321 GetOffTheRecordProfile())->GetDownloadManager(); 324 GetOffTheRecordProfile())->GetDownloadManager();
322 } 325 }
323 326
324 DownloadItem* GetActiveItemInternal( 327 DownloadItem* GetActiveItem(
325 Profile* profile, 328 Profile* profile,
326 bool include_incognito, 329 bool include_incognito,
327 int id) { 330 int id) {
328 DownloadManager* manager = NULL; 331 DownloadManager* manager = NULL;
329 DownloadManager* incognito_manager = NULL; 332 DownloadManager* incognito_manager = NULL;
330 GetManagers(profile, include_incognito, &manager, &incognito_manager); 333 GetManagers(profile, include_incognito, &manager, &incognito_manager);
331 DownloadItem* download_item = manager->GetActiveDownloadItem(id); 334 DownloadItem* download_item = manager->GetActiveDownloadItem(id);
332 if (!download_item && incognito_manager) 335 if (!download_item && incognito_manager)
333 download_item = incognito_manager->GetActiveDownloadItem(id); 336 download_item = incognito_manager->GetActiveDownloadItem(id);
334 return download_item; 337 return download_item;
335 } 338 }
336 339
340 enum DownloadsFunctionName {
341 DOWNLOADS_FUNCTION_DOWNLOAD = 0,
342 DOWNLOADS_FUNCTION_SEARCH = 1,
343 DOWNLOADS_FUNCTION_PAUSE = 2,
344 DOWNLOADS_FUNCTION_RESUME = 3,
345 DOWNLOADS_FUNCTION_CANCEL = 4,
346 DOWNLOADS_FUNCTION_ERASE = 5,
347 DOWNLOADS_FUNCTION_SET_DESTINATION = 6,
348 DOWNLOADS_FUNCTION_ACCEPT_DANGER = 7,
349 DOWNLOADS_FUNCTION_SHOW = 8,
350 DOWNLOADS_FUNCTION_DRAG = 9,
351 DOWNLOADS_FUNCTION_GET_FILE_ICON = 10,
352 DOWNLOADS_FUNCTION_OPEN = 11,
353 // Insert new values here, not at the beginning.
354 DOWNLOADS_FUNCTION_LAST
355 };
356
357 void RecordApiFunctions(DownloadsFunctionName function) {
358 UMA_HISTOGRAM_ENUMERATION("Download.ApiFunctions",
359 function,
360 DOWNLOADS_FUNCTION_LAST);
361 }
362
363 void CompileDownloadQueryOrderBy(
364 const std::string& order_by_str, std::string* error, DownloadQuery* query) {
365 static base::LazyInstance<SortTypeMap> sorter_types =
366 LAZY_INSTANCE_INITIALIZER;
367 if (sorter_types.Get().size() == 0)
368 InitSortTypeMap(sorter_types.Get());
369
370 std::vector<std::string> order_by_strs;
371 base::SplitString(order_by_str, ' ', &order_by_strs);
372 for (std::vector<std::string>::const_iterator iter = order_by_strs.begin();
373 iter != order_by_strs.end(); ++iter) {
374 std::string term_str = *iter;
375 if (term_str.empty())
376 continue;
377 DownloadQuery::SortDirection direction = DownloadQuery::ASCENDING;
378 if (term_str[0] == '-') {
379 direction = DownloadQuery::DESCENDING;
380 term_str = term_str.substr(1);
381 }
382 SortTypeMap::const_iterator sorter_type =
383 sorter_types.Get().find(term_str);
384 if (sorter_type == sorter_types.Get().end()) {
385 *error = download_extension_errors::kInvalidOrderByError;
386 return;
387 }
388 query->AddSorter(sorter_type->second, direction);
389 }
390 }
391
392 void RunDownloadQuery(
393 const extensions::api::downloads::DownloadQuery& query_in,
394 Profile* profile,
395 bool include_incognito,
396 std::string* error,
397 DownloadQuery::DownloadVector* results) {
398 static base::LazyInstance<FilterTypeMap> filter_types =
399 LAZY_INSTANCE_INITIALIZER;
400 if (filter_types.Get().size() == 0)
401 InitFilterTypeMap(filter_types.Get());
402
403 DownloadQuery query_out;
404
405 if (query_in.limit.get()) {
406 if (*query_in.limit.get() < 0) {
407 *error = download_extension_errors::kInvalidQueryLimit;
408 return;
409 }
410 query_out.Limit(*query_in.limit.get());
411 }
412 if (query_in.state.get()) {
413 DownloadItem::DownloadState state = StateEnumFromString(
414 *query_in.state.get());
415 if (state == DownloadItem::MAX_DOWNLOAD_STATE) {
416 *error = download_extension_errors::kInvalidStateError;
417 return;
418 }
419 query_out.AddFilter(state);
420 }
421 if (query_in.danger.get()) {
422 content::DownloadDangerType danger_type =
423 DangerEnumFromString(*query_in.danger.get());
424 if (danger_type == content::DOWNLOAD_DANGER_TYPE_MAX) {
425 *error = download_extension_errors::kInvalidDangerTypeError;
426 return;
427 }
428 query_out.AddFilter(danger_type);
429 }
430 if (query_in.order_by.get()) {
431 CompileDownloadQueryOrderBy(*query_in.order_by.get(), error, &query_out);
432 if (!error->empty())
433 return;
434 }
435
436 scoped_ptr<base::DictionaryValue> query_in_value(query_in.ToValue().Pass());
437 for (base::DictionaryValue::Iterator query_json_field(*query_in_value.get());
438 query_json_field.HasNext(); query_json_field.Advance()) {
439 FilterTypeMap::const_iterator filter_type =
440 filter_types.Get().find(query_json_field.key());
441 if (filter_type != filter_types.Get().end()) {
442 if (!query_out.AddFilter(filter_type->second, query_json_field.value())) {
443 *error = download_extension_errors::kInvalidFilterError;
444 return;
445 }
446 }
447 }
448
449 DownloadManager* manager = NULL;
450 DownloadManager* incognito_manager = NULL;
451 GetManagers(profile, include_incognito, &manager, &incognito_manager);
452 DownloadQuery::DownloadVector all_items;
453 if (query_in.id.get()) {
454 DownloadItem* item = manager->GetDownloadItem(*query_in.id.get());
455 if (!item && incognito_manager)
456 item = incognito_manager->GetDownloadItem(*query_in.id.get());
457 if (item)
458 all_items.push_back(item);
459 } else {
460 manager->GetAllDownloads(FilePath(FILE_PATH_LITERAL("")), &all_items);
461 if (incognito_manager)
462 incognito_manager->GetAllDownloads(
463 FilePath(FILE_PATH_LITERAL("")), &all_items);
464 }
465 query_out.Search(all_items.begin(), all_items.end(), results);
466 }
467
337 } // namespace 468 } // namespace
338 469
339 bool DownloadsFunctionInterface::RunImplImpl( 470 DownloadsDownloadFunction::DownloadsDownloadFunction() {}
340 DownloadsFunctionInterface* pimpl) {
341 CHECK(pimpl);
342 if (!pimpl->ParseArgs()) return false;
343 UMA_HISTOGRAM_ENUMERATION(
344 "Download.ApiFunctions", pimpl->function(), DOWNLOADS_FUNCTION_LAST);
345 return pimpl->RunInternal();
346 }
347
348 SyncDownloadsFunction::SyncDownloadsFunction(
349 DownloadsFunctionInterface::DownloadsFunctionName function)
350 : function_(function) {
351 }
352
353 SyncDownloadsFunction::~SyncDownloadsFunction() {}
354
355 bool SyncDownloadsFunction::RunImpl() {
356 return DownloadsFunctionInterface::RunImplImpl(this);
357 }
358
359 DownloadsFunctionInterface::DownloadsFunctionName
360 SyncDownloadsFunction::function() const {
361 return function_;
362 }
363
364 DownloadItem* SyncDownloadsFunction::GetActiveItem(int download_id) {
365 return GetActiveItemInternal(profile(), include_incognito(), download_id);
366 }
367
368 AsyncDownloadsFunction::AsyncDownloadsFunction(
369 DownloadsFunctionInterface::DownloadsFunctionName function)
370 : function_(function) {
371 }
372
373 AsyncDownloadsFunction::~AsyncDownloadsFunction() {}
374
375 bool AsyncDownloadsFunction::RunImpl() {
376 return DownloadsFunctionInterface::RunImplImpl(this);
377 }
378
379 DownloadsFunctionInterface::DownloadsFunctionName
380 AsyncDownloadsFunction::function() const {
381 return function_;
382 }
383
384 DownloadItem* AsyncDownloadsFunction::GetActiveItem(int download_id) {
385 return GetActiveItemInternal(profile(), include_incognito(), download_id);
386 }
387
388 DownloadsDownloadFunction::DownloadsDownloadFunction()
389 : AsyncDownloadsFunction(DOWNLOADS_FUNCTION_DOWNLOAD) {
390 }
391
392 DownloadsDownloadFunction::~DownloadsDownloadFunction() {} 471 DownloadsDownloadFunction::~DownloadsDownloadFunction() {}
393 472
394 DownloadsDownloadFunction::IOData::IOData() 473 bool DownloadsDownloadFunction::RunImpl() {
395 : save_as(false), 474 scoped_ptr<extensions::api::downloads::Download::Params> params(
396 extra_headers(NULL), 475 extensions::api::downloads::Download::Params::Create(*args_));
397 method("GET"), 476 EXTENSION_FUNCTION_VALIDATE(params.get());
398 rdh(NULL), 477 RecordApiFunctions(DOWNLOADS_FUNCTION_DOWNLOAD);
399 resource_context(NULL), 478 const extensions::api::downloads::DownloadOptions& options = params->options;
400 render_process_host_id(0), 479
401 render_view_host_routing_id(0) { 480 GURL url(options.url);
402 } 481 if (!url.is_valid() ||
403 482 (!url.SchemeIs("data") &&
404 DownloadsDownloadFunction::IOData::~IOData() {} 483 url.GetOrigin() != GetExtension()->url().GetOrigin() &&
405 484 !GetExtension()->HasHostPermission(url))) {
406 bool DownloadsDownloadFunction::ParseArgs() {
407 base::DictionaryValue* options = NULL;
408 std::string url;
409 iodata_.reset(new IOData());
410 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &options));
411 EXTENSION_FUNCTION_VALIDATE(options->GetString(kUrlKey, &url));
412 iodata_->url = GURL(url);
413 if (!iodata_->url.is_valid()) {
414 error_ = download_extension_errors::kInvalidURLError; 485 error_ = download_extension_errors::kInvalidURLError;
415 return false; 486 return false;
416 } 487 }
417 488
418 if (!iodata_->url.SchemeIs("data") && 489 content::DownloadSaveInfo save_info;
419 iodata_->url.GetOrigin() != GetExtension()->url().GetOrigin() && 490 if (options.filename.get()) {
420 !GetExtension()->HasHostPermission(iodata_->url)) { 491 // TODO(benjhayden): Make json_schema_compiler generate string16s instead of
421 error_ = download_extension_errors::kInvalidURLError; 492 // std::strings. Can't get filename16 from options.ToValue() because that
422 return false; 493 // converts it from std::string.
423 } 494 base::DictionaryValue* options_value = NULL;
424 495 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &options_value));
425 if (options->HasKey(kFilenameKey)) { 496 string16 filename16;
426 EXTENSION_FUNCTION_VALIDATE(options->GetString( 497 EXTENSION_FUNCTION_VALIDATE(options_value->GetString(
427 kFilenameKey, &iodata_->filename)); 498 kFilenameKey, &filename16));
428 if (!ValidateFilename(iodata_->filename)) { 499 if (!ValidateFilename(filename16)) {
429 error_ = download_extension_errors::kGenericError; 500 error_ = download_extension_errors::kGenericError;
430 return false; 501 return false;
431 } 502 }
432 } 503 // TODO(benjhayden) Ensure that this filename is interpreted as a path
433 504 // relative to the default downloads directory without allowing '..'.
434 if (options->HasKey(kSaveAsKey)) { 505 save_info.suggested_name = filename16;
435 EXTENSION_FUNCTION_VALIDATE(options->GetBoolean( 506 }
436 kSaveAsKey, &iodata_->save_as)); 507
437 } 508 if (options.save_as.get())
438 509 save_info.prompt_for_save_location = *options.save_as.get();
439 if (options->HasKey(kMethodKey)) { 510
440 EXTENSION_FUNCTION_VALIDATE(options->GetString( 511 Profile* current_profile = profile();
441 kMethodKey, &iodata_->method)); 512 if (include_incognito() && profile()->HasOffTheRecordProfile())
442 } 513 current_profile = profile()->GetOffTheRecordProfile();
443 514 // TODO XXX test incognito download()
444 // It's ok to use a pointer to extra_headers without DeepCopy()ing because 515
445 // |args_| (which owns *extra_headers) is guaranteed to live as long as 516 scoped_ptr<content::DownloadUrlParameters> download_params(
446 // |this|. 517 new content::DownloadUrlParameters(
447 if (options->HasKey(kHeadersKey)) { 518 url,
448 EXTENSION_FUNCTION_VALIDATE(options->GetList( 519 render_view_host()->GetProcess()->GetID(),
449 kHeadersKey, &iodata_->extra_headers)); 520 render_view_host()->GetRoutingID(),
450 } 521 current_profile->GetResourceContext(),
451 522 save_info));
452 if (options->HasKey(kBodyKey)) { 523
453 EXTENSION_FUNCTION_VALIDATE(options->GetString( 524 if (options.headers.get()) {
454 kBodyKey, &iodata_->post_body)); 525 for (std::vector<linked_ptr<HeaderNameValuePair> >::const_iterator iter =
455 } 526 options.headers->begin();
456 527 iter != options.headers->end();
457 if (iodata_->extra_headers != NULL) { 528 ++iter) {
458 for (size_t index = 0; index < iodata_->extra_headers->GetSize(); ++index) { 529 const HeaderNameValuePair& name_value = **iter;
459 base::DictionaryValue* header = NULL; 530 if (!net::HttpUtil::IsSafeHeader(name_value.name)) {
460 std::string name;
461 EXTENSION_FUNCTION_VALIDATE(iodata_->extra_headers->GetDictionary(
462 index, &header));
463 EXTENSION_FUNCTION_VALIDATE(header->GetString(
464 kHeaderNameKey, &name));
465 if (header->HasKey(kHeaderBinaryValueKey)) {
466 base::ListValue* binary_value = NULL;
467 EXTENSION_FUNCTION_VALIDATE(header->GetList(
468 kHeaderBinaryValueKey, &binary_value));
469 for (size_t char_i = 0; char_i < binary_value->GetSize(); ++char_i) {
470 int char_value = 0;
471 EXTENSION_FUNCTION_VALIDATE(binary_value->GetInteger(
472 char_i, &char_value));
473 }
474 } else if (header->HasKey(kHeaderValueKey)) {
475 std::string value;
476 EXTENSION_FUNCTION_VALIDATE(header->GetString(
477 kHeaderValueKey, &value));
478 }
479 if (!net::HttpUtil::IsSafeHeader(name)) {
480 error_ = download_extension_errors::kGenericError; 531 error_ = download_extension_errors::kGenericError;
481 return false; 532 return false;
482 } 533 }
483 } 534 std::string value;
484 } 535 if (name_value.binary_value.get()) {
485 iodata_->rdh = content::ResourceDispatcherHost::Get(); 536 for (size_t char_i = 0;
486 iodata_->resource_context = profile()->GetResourceContext(); 537 char_i < name_value.binary_value->size();
487 iodata_->render_process_host_id = render_view_host()->GetProcess()->GetID(); 538 ++char_i) {
488 iodata_->render_view_host_routing_id = render_view_host()->GetRoutingID(); 539 value.push_back((*name_value.binary_value.get())[char_i]);
540 }
541 } else if (name_value.value.get()) {
542 value = *name_value.value.get();
543 }
544 download_params->add_request_header(name_value.name, value);
545 }
546 }
547
548 if (options.method.get())
549 download_params->set_method(*options.method.get());
550 if (options.body.get())
551 download_params->set_post_body(*options.body.get());
552 download_params->set_callback(base::Bind(
553 &DownloadsDownloadFunction::OnStarted, this));
554 // Prevent login prompts for 401/407 responses.
555 download_params->set_load_flags(net::LOAD_DO_NOT_PROMPT_FOR_LOGIN);
556
557 DownloadManager* manager = DownloadServiceFactory::GetForProfile(
558 current_profile)->GetDownloadManager();
559 manager->DownloadUrl(download_params.Pass());
489 return true; 560 return true;
490 } 561 }
491 562
492 bool DownloadsDownloadFunction::RunInternal() {
493 VLOG(1) << __FUNCTION__ << " " << iodata_->url.spec();
494 if (!BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
495 &DownloadsDownloadFunction::BeginDownloadOnIOThread, this))) {
496 error_ = download_extension_errors::kGenericError;
497 return false;
498 }
499 return true;
500 }
501
502 void DownloadsDownloadFunction::BeginDownloadOnIOThread() {
503 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
504 DVLOG(1) << __FUNCTION__ << " " << iodata_->url.spec();
505 content::DownloadSaveInfo save_info;
506 // TODO(benjhayden) Ensure that this filename is interpreted as a path
507 // relative to the default downloads directory without allowing '..'.
508 save_info.suggested_name = iodata_->filename;
509 save_info.prompt_for_save_location = iodata_->save_as;
510
511 scoped_ptr<net::URLRequest> request(new net::URLRequest(iodata_->url, NULL));
512 request->set_method(iodata_->method);
513 if (iodata_->extra_headers != NULL) {
514 for (size_t index = 0; index < iodata_->extra_headers->GetSize(); ++index) {
515 base::DictionaryValue* header = NULL;
516 std::string name, value;
517 CHECK(iodata_->extra_headers->GetDictionary(index, &header));
518 CHECK(header->GetString(kHeaderNameKey, &name));
519 if (header->HasKey(kHeaderBinaryValueKey)) {
520 base::ListValue* binary_value = NULL;
521 CHECK(header->GetList(kHeaderBinaryValueKey, &binary_value));
522 for (size_t char_i = 0; char_i < binary_value->GetSize(); ++char_i) {
523 int char_value = 0;
524 CHECK(binary_value->GetInteger(char_i, &char_value));
525 if ((0 <= char_value) &&
526 (char_value <= 0xff)) {
527 value.push_back(char_value);
528 }
529 }
530 } else if (header->HasKey(kHeaderValueKey)) {
531 CHECK(header->GetString(kHeaderValueKey, &value));
532 }
533 request->SetExtraRequestHeaderByName(name, value, false/*overwrite*/);
534 }
535 }
536 if (!iodata_->post_body.empty()) {
537 request->AppendBytesToUpload(iodata_->post_body.data(),
538 iodata_->post_body.size());
539 }
540
541 // Prevent login prompts for 401/407 responses.
542 request->set_load_flags(request->load_flags() |
543 net::LOAD_DO_NOT_PROMPT_FOR_LOGIN);
544
545 net::Error error = iodata_->rdh->BeginDownload(
546 request.Pass(),
547 false, // is_content_initiated
548 iodata_->resource_context,
549 iodata_->render_process_host_id,
550 iodata_->render_view_host_routing_id,
551 false, // prefer_cache
552 save_info,
553 base::Bind(&DownloadsDownloadFunction::OnStarted, this));
554 iodata_.reset();
555
556 if (error != net::OK) {
557 BrowserThread::PostTask(
558 BrowserThread::UI, FROM_HERE,
559 base::Bind(&DownloadsDownloadFunction::OnStarted, this,
560 DownloadId::Invalid(), error));
561 }
562 }
563
564 void DownloadsDownloadFunction::OnStarted(DownloadId dl_id, net::Error error) { 563 void DownloadsDownloadFunction::OnStarted(DownloadId dl_id, net::Error error) {
565 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 564 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
566 VLOG(1) << __FUNCTION__ << " " << dl_id << " " << error; 565 VLOG(1) << __FUNCTION__ << " " << dl_id << " " << error;
567 if (dl_id.local() >= 0) { 566 if (dl_id.local() >= 0) {
568 result_.reset(base::Value::CreateIntegerValue(dl_id.local())); 567 result_.reset(base::Value::CreateIntegerValue(dl_id.local()));
569 } else { 568 } else {
570 error_ = net::ErrorToString(error); 569 error_ = net::ErrorToString(error);
571 } 570 }
572 SendResponse(error_.empty()); 571 SendResponse(error_.empty());
573 } 572 }
574 573
575 DownloadsSearchFunction::DownloadsSearchFunction() 574 DownloadsSearchFunction::DownloadsSearchFunction() {}
576 : SyncDownloadsFunction(DOWNLOADS_FUNCTION_SEARCH),
577 query_(new DownloadQuery()),
578 get_id_(0),
579 has_get_id_(false) {
580 }
581
582 DownloadsSearchFunction::~DownloadsSearchFunction() {} 575 DownloadsSearchFunction::~DownloadsSearchFunction() {}
583 576
584 bool DownloadsSearchFunction::ParseArgs() { 577 bool DownloadsSearchFunction::RunImpl() {
585 static base::LazyInstance<FilterTypeMap> filter_types = 578 scoped_ptr<extensions::api::downloads::Search::Params> params(
586 LAZY_INSTANCE_INITIALIZER; 579 extensions::api::downloads::Search::Params::Create(*args_));
587 if (filter_types.Get().size() == 0) 580 EXTENSION_FUNCTION_VALIDATE(params.get());
588 InitFilterTypeMap(filter_types.Get()); 581 RecordApiFunctions(DOWNLOADS_FUNCTION_SEARCH);
589 582 DownloadQuery::DownloadVector results;
590 base::DictionaryValue* query_json = NULL; 583 RunDownloadQuery(params->query, profile(), include_incognito(),
591 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &query_json)); 584 &error_, &results);
592 for (base::DictionaryValue::Iterator query_json_field(*query_json); 585 if (!error_.empty())
593 query_json_field.HasNext(); query_json_field.Advance()) { 586 return false;
594 FilterTypeMap::const_iterator filter_type =
595 filter_types.Get().find(query_json_field.key());
596
597 if (filter_type != filter_types.Get().end()) {
598 if (!query_->AddFilter(filter_type->second, query_json_field.value())) {
599 error_ = download_extension_errors::kInvalidFilterError;
600 return false;
601 }
602 } else if (query_json_field.key() == kIdKey) {
603 EXTENSION_FUNCTION_VALIDATE(query_json_field.value().GetAsInteger(
604 &get_id_));
605 has_get_id_ = true;
606 } else if (query_json_field.key() == kOrderByKey) {
607 if (!ParseOrderBy(query_json_field.value()))
608 return false;
609 } else if (query_json_field.key() == kDangerKey) {
610 std::string danger_str;
611 EXTENSION_FUNCTION_VALIDATE(query_json_field.value().GetAsString(
612 &danger_str));
613 content::DownloadDangerType danger_type =
614 DangerEnumFromString(danger_str);
615 if (danger_type == content::DOWNLOAD_DANGER_TYPE_MAX) {
616 error_ = download_extension_errors::kInvalidDangerTypeError;
617 return false;
618 }
619 query_->AddFilter(danger_type);
620 } else if (query_json_field.key() == kStateKey) {
621 std::string state_str;
622 EXTENSION_FUNCTION_VALIDATE(query_json_field.value().GetAsString(
623 &state_str));
624 DownloadItem::DownloadState state = StateEnumFromString(state_str);
625 if (state == DownloadItem::MAX_DOWNLOAD_STATE) {
626 error_ = download_extension_errors::kInvalidStateError;
627 return false;
628 }
629 query_->AddFilter(state);
630 } else if (query_json_field.key() == kLimitKey) {
631 int limit = 0;
632 EXTENSION_FUNCTION_VALIDATE(query_json_field.value().GetAsInteger(
633 &limit));
634 if (limit < 0) {
635 error_ = download_extension_errors::kInvalidQueryLimit;
636 return false;
637 }
638 query_->Limit(limit);
639 } else {
640 EXTENSION_FUNCTION_VALIDATE(false);
641 }
642 }
643 return true;
644 }
645
646 bool DownloadsSearchFunction::ParseOrderBy(const base::Value& order_by_value) {
647 static base::LazyInstance<SortTypeMap> sorter_types =
648 LAZY_INSTANCE_INITIALIZER;
649 if (sorter_types.Get().size() == 0)
650 InitSortTypeMap(sorter_types.Get());
651
652 std::string order_by_str;
653 EXTENSION_FUNCTION_VALIDATE(order_by_value.GetAsString(&order_by_str));
654 std::vector<std::string> order_by_strs;
655 base::SplitString(order_by_str, ' ', &order_by_strs);
656 for (std::vector<std::string>::const_iterator iter = order_by_strs.begin();
657 iter != order_by_strs.end(); ++iter) {
658 std::string term_str = *iter;
659 if (term_str.empty())
660 continue;
661 DownloadQuery::SortDirection direction = DownloadQuery::ASCENDING;
662 if (term_str[0] == '-') {
663 direction = DownloadQuery::DESCENDING;
664 term_str = term_str.substr(1);
665 }
666 SortTypeMap::const_iterator sorter_type =
667 sorter_types.Get().find(term_str);
668 if (sorter_type == sorter_types.Get().end()) {
669 error_ = download_extension_errors::kInvalidOrderByError;
670 return false;
671 }
672 query_->AddSorter(sorter_type->second, direction);
673 }
674 return true;
675 }
676
677 bool DownloadsSearchFunction::RunInternal() {
678 DownloadManager* manager = NULL;
679 DownloadManager* incognito_manager = NULL;
680 GetManagers(profile(), include_incognito(), &manager, &incognito_manager);
681 DownloadQuery::DownloadVector all_items, cpp_results;
682 if (has_get_id_) {
683 DownloadItem* item = manager->GetDownloadItem(get_id_);
684 if (!item && incognito_manager)
685 item = incognito_manager->GetDownloadItem(get_id_);
686 if (item)
687 all_items.push_back(item);
688 } else {
689 manager->GetAllDownloads(FilePath(FILE_PATH_LITERAL("")), &all_items);
690 if (incognito_manager)
691 incognito_manager->GetAllDownloads(
692 FilePath(FILE_PATH_LITERAL("")), &all_items);
693 }
694 query_->Search(all_items.begin(), all_items.end(), &cpp_results);
695 base::ListValue* json_results = new base::ListValue(); 587 base::ListValue* json_results = new base::ListValue();
696 for (DownloadManager::DownloadVector::const_iterator it = cpp_results.begin(); 588 for (DownloadManager::DownloadVector::const_iterator it = results.begin();
697 it != cpp_results.end(); ++it) { 589 it != results.end(); ++it) {
698 scoped_ptr<base::DictionaryValue> item(DownloadItemToJSON(*it)); 590 scoped_ptr<base::DictionaryValue> item(DownloadItemToJSON(*it));
699 json_results->Append(item.release()); 591 json_results->Append(item.release());
700 } 592 }
701 result_.reset(json_results); 593 result_.reset(json_results);
702 return true; 594 return true;
703 } 595 }
704 596
705 DownloadsPauseFunction::DownloadsPauseFunction() 597 DownloadsPauseFunction::DownloadsPauseFunction() {}
706 : SyncDownloadsFunction(DOWNLOADS_FUNCTION_PAUSE),
707 download_id_(DownloadId::Invalid().local()) {
708 }
709
710 DownloadsPauseFunction::~DownloadsPauseFunction() {} 598 DownloadsPauseFunction::~DownloadsPauseFunction() {}
711 599
712 bool DownloadsPauseFunction::ParseArgs() { 600 bool DownloadsPauseFunction::RunImpl() {
713 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &download_id_)); 601 scoped_ptr<extensions::api::downloads::Pause::Params> params(
714 return true; 602 extensions::api::downloads::Pause::Params::Create(*args_));
715 } 603 EXTENSION_FUNCTION_VALIDATE(params.get());
716 604 RecordApiFunctions(DOWNLOADS_FUNCTION_PAUSE);
717 bool DownloadsPauseFunction::RunInternal() { 605 DownloadItem* download_item = GetActiveItem(
718 DownloadItem* download_item = GetActiveItem(download_id_); 606 profile(), include_incognito(), params->download_id);
719 if ((download_item == NULL) || !download_item->IsInProgress()) { 607 if ((download_item == NULL) || !download_item->IsInProgress()) {
720 // This could be due to an invalid download ID, or it could be due to the 608 // This could be due to an invalid download ID, or it could be due to the
721 // download not being currently active. 609 // download not being currently active.
722 error_ = download_extension_errors::kInvalidOperationError; 610 error_ = download_extension_errors::kInvalidOperationError;
723 } else if (!download_item->IsPaused()) { 611 } else if (!download_item->IsPaused()) {
724 // If download_item->IsPaused() already then we treat it as a success. 612 // If download_item->IsPaused() already then we treat it as a success.
725 download_item->TogglePause(); 613 download_item->TogglePause();
726 } 614 }
727 return error_.empty(); 615 return error_.empty();
728 } 616 }
729 617
730 DownloadsResumeFunction::DownloadsResumeFunction() 618 DownloadsResumeFunction::DownloadsResumeFunction() {}
731 : SyncDownloadsFunction(DOWNLOADS_FUNCTION_RESUME),
732 download_id_(DownloadId::Invalid().local()) {
733 }
734
735 DownloadsResumeFunction::~DownloadsResumeFunction() {} 619 DownloadsResumeFunction::~DownloadsResumeFunction() {}
736 620
737 bool DownloadsResumeFunction::ParseArgs() { 621 bool DownloadsResumeFunction::RunImpl() {
738 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &download_id_)); 622 scoped_ptr<extensions::api::downloads::Resume::Params> params(
739 return true; 623 extensions::api::downloads::Resume::Params::Create(*args_));
740 } 624 EXTENSION_FUNCTION_VALIDATE(params.get());
741 625 RecordApiFunctions(DOWNLOADS_FUNCTION_RESUME);
742 bool DownloadsResumeFunction::RunInternal() { 626 DownloadItem* download_item = GetActiveItem(
743 DownloadItem* download_item = GetActiveItem(download_id_); 627 profile(), include_incognito(), params->download_id);
744 if (download_item == NULL) { 628 if (download_item == NULL) {
745 // This could be due to an invalid download ID, or it could be due to the 629 // This could be due to an invalid download ID, or it could be due to the
746 // download not being currently active. 630 // download not being currently active.
747 error_ = download_extension_errors::kInvalidOperationError; 631 error_ = download_extension_errors::kInvalidOperationError;
748 } else if (download_item->IsPaused()) { 632 } else if (download_item->IsPaused()) {
749 // If !download_item->IsPaused() already, then we treat it as a success. 633 // If !download_item->IsPaused() already, then we treat it as a success.
750 download_item->TogglePause(); 634 download_item->TogglePause();
751 } 635 }
752 return error_.empty(); 636 return error_.empty();
753 } 637 }
754 638
755 DownloadsCancelFunction::DownloadsCancelFunction() 639 DownloadsCancelFunction::DownloadsCancelFunction() {}
756 : SyncDownloadsFunction(DOWNLOADS_FUNCTION_CANCEL),
757 download_id_(DownloadId::Invalid().local()) {
758 }
759
760 DownloadsCancelFunction::~DownloadsCancelFunction() {} 640 DownloadsCancelFunction::~DownloadsCancelFunction() {}
761 641
762 bool DownloadsCancelFunction::ParseArgs() { 642 bool DownloadsCancelFunction::RunImpl() {
763 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &download_id_)); 643 scoped_ptr<extensions::api::downloads::Resume::Params> params(
764 return true; 644 extensions::api::downloads::Resume::Params::Create(*args_));
765 } 645 EXTENSION_FUNCTION_VALIDATE(params.get());
766 646 RecordApiFunctions(DOWNLOADS_FUNCTION_CANCEL);
767 bool DownloadsCancelFunction::RunInternal() { 647 DownloadItem* download_item = GetActiveItem(
768 DownloadItem* download_item = GetActiveItem(download_id_); 648 profile(), include_incognito(), params->download_id);
769 if (download_item != NULL) 649 if (download_item != NULL)
770 download_item->Cancel(true); 650 download_item->Cancel(true);
771 // |download_item| can be NULL if the download ID was invalid or if the 651 // |download_item| can be NULL if the download ID was invalid or if the
772 // download is not currently active. Either way, we don't consider it a 652 // download is not currently active. Either way, we don't consider it a
773 // failure. 653 // failure.
774 return error_.empty(); 654 return error_.empty();
775 } 655 }
776 656
777 DownloadsEraseFunction::DownloadsEraseFunction() 657 DownloadsEraseFunction::DownloadsEraseFunction() {}
778 : AsyncDownloadsFunction(DOWNLOADS_FUNCTION_ERASE) { 658 DownloadsEraseFunction::~DownloadsEraseFunction() {}
659
660 bool DownloadsEraseFunction::RunImpl() {
661 scoped_ptr<extensions::api::downloads::Erase::Params> params(
662 extensions::api::downloads::Erase::Params::Create(*args_));
663 EXTENSION_FUNCTION_VALIDATE(params.get());
664 RecordApiFunctions(DOWNLOADS_FUNCTION_ERASE);
665 error_ = download_extension_errors::kNotImplementedError;
666 return error_.empty();
779 } 667 }
780 668
781 DownloadsEraseFunction::~DownloadsEraseFunction() {} 669 DownloadsSetDestinationFunction::DownloadsSetDestinationFunction() {}
670 DownloadsSetDestinationFunction::~DownloadsSetDestinationFunction() {}
782 671
783 bool DownloadsEraseFunction::ParseArgs() { 672 bool DownloadsSetDestinationFunction::RunImpl() {
784 base::DictionaryValue* query_json = NULL; 673 scoped_ptr<extensions::api::downloads::SetDestination::Params> params(
785 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &query_json)); 674 extensions::api::downloads::SetDestination::Params::Create(*args_));
675 EXTENSION_FUNCTION_VALIDATE(params.get());
676 RecordApiFunctions(DOWNLOADS_FUNCTION_SET_DESTINATION);
786 error_ = download_extension_errors::kNotImplementedError; 677 error_ = download_extension_errors::kNotImplementedError;
787 return false; 678 return error_.empty();
788 } 679 }
789 680
790 bool DownloadsEraseFunction::RunInternal() { 681 DownloadsAcceptDangerFunction::DownloadsAcceptDangerFunction() {}
791 NOTIMPLEMENTED(); 682 DownloadsAcceptDangerFunction::~DownloadsAcceptDangerFunction() {}
792 return false; 683
684 bool DownloadsAcceptDangerFunction::RunImpl() {
685 scoped_ptr<extensions::api::downloads::AcceptDanger::Params> params(
686 extensions::api::downloads::AcceptDanger::Params::Create(*args_));
687 EXTENSION_FUNCTION_VALIDATE(params.get());
688 RecordApiFunctions(DOWNLOADS_FUNCTION_ACCEPT_DANGER);
689 error_ = download_extension_errors::kNotImplementedError;
690 return error_.empty();
793 } 691 }
794 692
795 DownloadsSetDestinationFunction::DownloadsSetDestinationFunction() 693 DownloadsShowFunction::DownloadsShowFunction() {}
796 : AsyncDownloadsFunction(DOWNLOADS_FUNCTION_SET_DESTINATION) { 694 DownloadsShowFunction::~DownloadsShowFunction() {}
695
696 bool DownloadsShowFunction::RunImpl() {
697 scoped_ptr<extensions::api::downloads::Show::Params> params(
698 extensions::api::downloads::Show::Params::Create(*args_));
699 EXTENSION_FUNCTION_VALIDATE(params.get());
700 RecordApiFunctions(DOWNLOADS_FUNCTION_SHOW);
701 error_ = download_extension_errors::kNotImplementedError;
702 return error_.empty();
797 } 703 }
798 704
799 DownloadsSetDestinationFunction::~DownloadsSetDestinationFunction() {} 705 DownloadsOpenFunction::DownloadsOpenFunction() {}
706 DownloadsOpenFunction::~DownloadsOpenFunction() {}
800 707
801 bool DownloadsSetDestinationFunction::ParseArgs() { 708 bool DownloadsOpenFunction::RunImpl() {
802 int dl_id = 0; 709 scoped_ptr<extensions::api::downloads::Open::Params> params(
803 std::string path; 710 extensions::api::downloads::Open::Params::Create(*args_));
804 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &dl_id)); 711 EXTENSION_FUNCTION_VALIDATE(params.get());
805 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &path)); 712 RecordApiFunctions(DOWNLOADS_FUNCTION_OPEN);
806 VLOG(1) << __FUNCTION__ << " " << dl_id << " " << &path;
807 error_ = download_extension_errors::kNotImplementedError; 713 error_ = download_extension_errors::kNotImplementedError;
808 return false; 714 return error_.empty();
809 } 715 }
810 716
811 bool DownloadsSetDestinationFunction::RunInternal() { 717 DownloadsDragFunction::DownloadsDragFunction() {}
812 NOTIMPLEMENTED();
813 return false;
814 }
815
816 DownloadsAcceptDangerFunction::DownloadsAcceptDangerFunction()
817 : AsyncDownloadsFunction(DOWNLOADS_FUNCTION_ACCEPT_DANGER) {
818 }
819
820 DownloadsAcceptDangerFunction::~DownloadsAcceptDangerFunction() {}
821
822 bool DownloadsAcceptDangerFunction::ParseArgs() {
823 int dl_id = 0;
824 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &dl_id));
825 VLOG(1) << __FUNCTION__ << " " << dl_id;
826 error_ = download_extension_errors::kNotImplementedError;
827 return false;
828 }
829
830 bool DownloadsAcceptDangerFunction::RunInternal() {
831 NOTIMPLEMENTED();
832 return false;
833 }
834
835 DownloadsShowFunction::DownloadsShowFunction()
836 : AsyncDownloadsFunction(DOWNLOADS_FUNCTION_SHOW) {
837 }
838
839 DownloadsShowFunction::~DownloadsShowFunction() {}
840
841 bool DownloadsShowFunction::ParseArgs() {
842 int dl_id = 0;
843 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &dl_id));
844 VLOG(1) << __FUNCTION__ << " " << dl_id;
845 error_ = download_extension_errors::kNotImplementedError;
846 return false;
847 }
848
849 bool DownloadsShowFunction::RunInternal() {
850 NOTIMPLEMENTED();
851 return false;
852 }
853
854 DownloadsDragFunction::DownloadsDragFunction()
855 : AsyncDownloadsFunction(DOWNLOADS_FUNCTION_DRAG) {
856 }
857
858 DownloadsDragFunction::~DownloadsDragFunction() {} 718 DownloadsDragFunction::~DownloadsDragFunction() {}
859 719
860 bool DownloadsDragFunction::ParseArgs() { 720 bool DownloadsDragFunction::RunImpl() {
861 int dl_id = 0; 721 scoped_ptr<extensions::api::downloads::Drag::Params> params(
862 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &dl_id)); 722 extensions::api::downloads::Drag::Params::Create(*args_));
863 VLOG(1) << __FUNCTION__ << " " << dl_id; 723 EXTENSION_FUNCTION_VALIDATE(params.get());
724 RecordApiFunctions(DOWNLOADS_FUNCTION_DRAG);
864 error_ = download_extension_errors::kNotImplementedError; 725 error_ = download_extension_errors::kNotImplementedError;
865 return false; 726 return error_.empty();
866 }
867
868 bool DownloadsDragFunction::RunInternal() {
869 NOTIMPLEMENTED();
870 return false;
871 } 727 }
872 728
873 DownloadsGetFileIconFunction::DownloadsGetFileIconFunction() 729 DownloadsGetFileIconFunction::DownloadsGetFileIconFunction()
874 : AsyncDownloadsFunction(DOWNLOADS_FUNCTION_GET_FILE_ICON), 730 : icon_extractor_(new DownloadFileIconExtractorImpl()) {
875 icon_size_(kDefaultIconSize),
876 icon_extractor_(new DownloadFileIconExtractorImpl()) {
877 } 731 }
878 732
879 DownloadsGetFileIconFunction::~DownloadsGetFileIconFunction() {} 733 DownloadsGetFileIconFunction::~DownloadsGetFileIconFunction() {}
880 734
881 void DownloadsGetFileIconFunction::SetIconExtractorForTesting( 735 void DownloadsGetFileIconFunction::SetIconExtractorForTesting(
882 DownloadFileIconExtractor* extractor) { 736 DownloadFileIconExtractor* extractor) {
883 DCHECK(extractor); 737 DCHECK(extractor);
884 icon_extractor_.reset(extractor); 738 icon_extractor_.reset(extractor);
885 } 739 }
886 740
887 bool DownloadsGetFileIconFunction::ParseArgs() { 741 bool DownloadsGetFileIconFunction::RunImpl() {
888 int dl_id = 0; 742 scoped_ptr<extensions::api::downloads::GetFileIcon::Params> params(
889 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &dl_id)); 743 extensions::api::downloads::GetFileIcon::Params::Create(*args_));
890 744 EXTENSION_FUNCTION_VALIDATE(params.get());
891 base::DictionaryValue* options = NULL; 745 UMA_HISTOGRAM_ENUMERATION("Download.ApiFunctions",
892 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &options)); 746 DOWNLOADS_FUNCTION_GET_FILE_ICON,
893 if (options->HasKey(kSizeKey)) { 747 DOWNLOADS_FUNCTION_LAST);
894 EXTENSION_FUNCTION_VALIDATE(options->GetInteger(kSizeKey, &icon_size_)); 748 const extensions::api::downloads::GetFileIconOptions* options =
895 // We only support 16px and 32px icons. This is enforced in 749 params->options.get();
896 // experimental.downloads.json. 750 int icon_size = kDefaultIconSize;
897 DCHECK(icon_size_ == 16 || icon_size_ == 32); 751 if (options && options->size.get())
898 } 752 icon_size = *options->size.get();
899
900 DownloadManager* manager = NULL; 753 DownloadManager* manager = NULL;
901 DownloadManager* incognito_manager = NULL; 754 DownloadManager* incognito_manager = NULL;
902 GetManagers(profile(), include_incognito(), &manager, &incognito_manager); 755 GetManagers(profile(), include_incognito(), &manager, &incognito_manager);
903 DownloadItem* download_item = manager->GetDownloadItem(dl_id); 756 DownloadItem* download_item = manager->GetDownloadItem(params->download_id);
904 if (!download_item && incognito_manager) 757 if (!download_item && incognito_manager)
905 download_item = incognito_manager->GetDownloadItem(dl_id); 758 download_item = incognito_manager->GetDownloadItem(params->download_id);
906 if (!download_item) { 759 if (!download_item) {
907 // The DownloadItem is is added to history when the path is determined. If 760 // The DownloadItem is is added to history when the path is determined. If
908 // the download is not in history, then we don't have a path / final 761 // the download is not in history, then we don't have a path / final
909 // filename and no icon. 762 // filename and no icon.
910 error_ = download_extension_errors::kInvalidOperationError; 763 error_ = download_extension_errors::kInvalidOperationError;
911 return false; 764 return false;
912 } 765 }
913 // In-progress downloads return the intermediate filename for GetFullPath() 766 // In-progress downloads return the intermediate filename for GetFullPath()
914 // which doesn't have the final extension. Therefore we won't be able to 767 // which doesn't have the final extension. Therefore we won't be able to
915 // derive a good file icon for it. So we use GetTargetFilePath() instead. 768 // derive a good file icon for it. So we use GetTargetFilePath() instead.
916 path_ = download_item->GetTargetFilePath(); 769 FilePath path = download_item->GetTargetFilePath();
917 DCHECK(!path_.empty()); 770 DCHECK(!path.empty());
918 return true;
919 }
920
921 bool DownloadsGetFileIconFunction::RunInternal() {
922 DCHECK(!path_.empty());
923 DCHECK(icon_extractor_.get()); 771 DCHECK(icon_extractor_.get());
772 DCHECK(icon_size == 16 || icon_size == 32);
924 EXTENSION_FUNCTION_VALIDATE(icon_extractor_->ExtractIconURLForPath( 773 EXTENSION_FUNCTION_VALIDATE(icon_extractor_->ExtractIconURLForPath(
925 path_, IconLoaderSizeFromPixelSize(icon_size_), 774 path, IconLoaderSizeFromPixelSize(icon_size),
926 base::Bind(&DownloadsGetFileIconFunction::OnIconURLExtracted, this))); 775 base::Bind(&DownloadsGetFileIconFunction::OnIconURLExtracted, this)));
927 return true; 776 return true;
928 } 777 }
929 778
930 void DownloadsGetFileIconFunction::OnIconURLExtracted(const std::string& url) { 779 void DownloadsGetFileIconFunction::OnIconURLExtracted(const std::string& url) {
931 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 780 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
932 if (url.empty()) 781 if (url.empty())
933 error_ = download_extension_errors::kIconNotFoundError; 782 error_ = download_extension_errors::kIconNotFoundError;
934 else 783 else
935 result_.reset(base::Value::CreateStringValue(url)); 784 result_.reset(base::Value::CreateStringValue(url));
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
1010 // set the differences in the |delta| object and remember that something 859 // set the differences in the |delta| object and remember that something
1011 // significant changed. 860 // significant changed.
1012 for (base::DictionaryValue::Iterator iter(*new_json.get()); 861 for (base::DictionaryValue::Iterator iter(*new_json.get());
1013 iter.HasNext(); iter.Advance()) { 862 iter.HasNext(); iter.Advance()) {
1014 new_fields.insert(iter.key()); 863 new_fields.insert(iter.key());
1015 if (iter.key() != kBytesReceivedKey) { 864 if (iter.key() != kBytesReceivedKey) {
1016 base::Value* old_value = NULL; 865 base::Value* old_value = NULL;
1017 if (!old_json->HasKey(iter.key()) || 866 if (!old_json->HasKey(iter.key()) ||
1018 (old_json->Get(iter.key(), &old_value) && 867 (old_json->Get(iter.key(), &old_value) &&
1019 !iter.value().Equals(old_value))) { 868 !iter.value().Equals(old_value))) {
1020 delta->Set(iter.key() + ".new", iter.value().DeepCopy()); 869 delta->Set(iter.key() + ".current", iter.value().DeepCopy());
1021 if (old_value) 870 if (old_value)
1022 delta->Set(iter.key() + ".old", old_value->DeepCopy()); 871 delta->Set(iter.key() + ".previous", old_value->DeepCopy());
1023 changed = true; 872 changed = true;
1024 } 873 }
1025 } 874 }
1026 } 875 }
1027 876
1028 // If a field was in the previous json but is not in the new json, set the 877 // If a field was in the previous json but is not in the new json, set the
1029 // difference in |delta|. 878 // difference in |delta|.
1030 for (base::DictionaryValue::Iterator iter(*old_json); 879 for (base::DictionaryValue::Iterator iter(*old_json);
1031 iter.HasNext(); iter.Advance()) { 880 iter.HasNext(); iter.Advance()) {
1032 if (new_fields.find(iter.key()) == new_fields.end()) { 881 if (new_fields.find(iter.key()) == new_fields.end()) {
1033 delta->Set(iter.key() + ".old", iter.value().DeepCopy()); 882 delta->Set(iter.key() + ".previous", iter.value().DeepCopy());
1034 changed = true; 883 changed = true;
1035 } 884 }
1036 } 885 }
1037 886
1038 // Update the OnChangedStat and dispatch the event if something significant 887 // Update the OnChangedStat and dispatch the event if something significant
1039 // changed. Replace the stored json with the new json. 888 // changed. Replace the stored json with the new json.
1040 ++(on_changed_stats_[download_id]->total); 889 ++(on_changed_stats_[download_id]->total);
1041 if (changed) { 890 if (changed) {
1042 DispatchEvent(extension_event_names::kOnDownloadChanged, delta.release()); 891 DispatchEvent(extension_event_names::kOnDownloadChanged, delta.release());
1043 ++(on_changed_stats_[download_id]->fires); 892 ++(on_changed_stats_[download_id]->fires);
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
1112 ListValue args; 961 ListValue args;
1113 args.Append(arg); 962 args.Append(arg);
1114 std::string json_args; 963 std::string json_args;
1115 base::JSONWriter::Write(&args, &json_args); 964 base::JSONWriter::Write(&args, &json_args);
1116 profile_->GetExtensionEventRouter()->DispatchEventToRenderers( 965 profile_->GetExtensionEventRouter()->DispatchEventToRenderers(
1117 event_name, 966 event_name,
1118 json_args, 967 json_args,
1119 profile_, 968 profile_,
1120 GURL()); 969 GURL());
1121 } 970 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698