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
3// found in the LICENSE file.
4
5#include <algorithm>
6
7#include "base/file_util.h"
8#include "base/files/scoped_temp_dir.h"
9#include "base/json/json_reader.h"
10#include "base/message_loop/message_loop.h"
11#include "base/prefs/pref_service.h"
12#include "base/stl_util.h"
13#include "base/strings/stringprintf.h"
14#include "base/synchronization/waitable_event.h"
15#include "chrome/browser/chrome_notification_types.h"
16#include "chrome/browser/download/download_file_icon_extractor.h"
17#include "chrome/browser/download/download_service.h"
18#include "chrome/browser/download/download_service_factory.h"
19#include "chrome/browser/download/download_test_file_activity_observer.h"
20#include "chrome/browser/extensions/api/downloads/downloads_api.h"
21#include "chrome/browser/extensions/event_names.h"
22#include "chrome/browser/extensions/extension_apitest.h"
23#include "chrome/browser/extensions/extension_function_test_utils.h"
24#include "chrome/browser/extensions/extension_service.h"
25#include "chrome/browser/history/download_row.h"
26#include "chrome/browser/net/url_request_mock_util.h"
27#include "chrome/browser/profiles/profile.h"
28#include "chrome/browser/ui/browser.h"
29#include "chrome/browser/ui/browser_tabstrip.h"
30#include "chrome/common/pref_names.h"
31#include "chrome/test/base/in_process_browser_test.h"
32#include "chrome/test/base/ui_test_utils.h"
33#include "content/public/browser/browser_context.h"
34#include "content/public/browser/browser_thread.h"
35#include "content/public/browser/download_item.h"
36#include "content/public/browser/download_manager.h"
37#include "content/public/browser/notification_service.h"
38#include "content/public/browser/storage_partition.h"
39#include "content/public/browser/web_contents.h"
40#include "content/public/common/content_switches.h"
41#include "content/public/common/page_transition_types.h"
42#include "content/public/test/download_test_observer.h"
43#include "content/test/net/url_request_slow_download_job.h"
44#include "net/base/data_url.h"
45#include "net/base/net_util.h"
46#include "net/url_request/url_request.h"
47#include "net/url_request/url_request_context.h"
48#include "net/url_request/url_request_job.h"
49#include "net/url_request/url_request_job_factory.h"
50#include "net/url_request/url_request_job_factory_impl.h"
51#include "webkit/browser/fileapi/file_system_context.h"
52#include "webkit/browser/fileapi/file_system_operation_runner.h"
53#include "webkit/browser/fileapi/file_system_url.h"
54
55using content::BrowserContext;
56using content::BrowserThread;
57using content::DownloadItem;
58using content::DownloadManager;
59using content::URLRequestSlowDownloadJob;
60
61namespace events = extensions::event_names;
62
63namespace errors = download_extension_errors;
64
65namespace api = extensions::api::downloads;
66
67namespace {
68
69// Comparator that orders download items by their ID. Can be used with
70// std::sort.
71struct DownloadIdComparator {
72  bool operator() (DownloadItem* first, DownloadItem* second) {
73    return first->GetId() < second->GetId();
74  }
75};
76
77class DownloadsEventsListener : public content::NotificationObserver {
78 public:
79  DownloadsEventsListener()
80    : waiting_(false) {
81    registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_DOWNLOADS_EVENT,
82                   content::NotificationService::AllSources());
83  }
84
85  virtual ~DownloadsEventsListener() {
86    registrar_.Remove(this, chrome::NOTIFICATION_EXTENSION_DOWNLOADS_EVENT,
87                      content::NotificationService::AllSources());
88    STLDeleteElements(&events_);
89  }
90
91  void ClearEvents() {
92    STLDeleteElements(&events_);
93    events_.clear();
94  }
95
96  class Event {
97   public:
98    Event(Profile* profile,
99          const std::string& event_name,
100          const std::string& json_args,
101          base::Time caught)
102      : profile_(profile),
103        event_name_(event_name),
104        json_args_(json_args),
105        args_(base::JSONReader::Read(json_args)),
106        caught_(caught) {
107    }
108
109    const base::Time& caught() { return caught_; }
110
111    bool Satisfies(const Event& other) const {
112      return other.SatisfiedBy(*this);
113    }
114
115    bool SatisfiedBy(const Event& other) const {
116      if ((profile_ != other.profile_) ||
117          (event_name_ != other.event_name_))
118        return false;
119      if (((event_name_ == events::kOnDownloadDeterminingFilename) ||
120           (event_name_ == events::kOnDownloadCreated) ||
121           (event_name_ == events::kOnDownloadChanged)) &&
122          args_.get() &&
123          other.args_.get()) {
124        base::ListValue* left_list = NULL;
125        base::DictionaryValue* left_dict = NULL;
126        base::ListValue* right_list = NULL;
127        base::DictionaryValue* right_dict = NULL;
128        if (!args_->GetAsList(&left_list) ||
129            !other.args_->GetAsList(&right_list) ||
130            !left_list->GetDictionary(0, &left_dict) ||
131            !right_list->GetDictionary(0, &right_dict))
132          return false;
133        for (base::DictionaryValue::Iterator iter(*left_dict);
134             !iter.IsAtEnd(); iter.Advance()) {
135          base::Value* right_value = NULL;
136          if (!right_dict->HasKey(iter.key()) ||
137              (right_dict->Get(iter.key(), &right_value) &&
138               !iter.value().Equals(right_value))) {
139            return false;
140          }
141        }
142        return true;
143      } else if ((event_name_ == events::kOnDownloadErased) &&
144                 args_.get() &&
145                 other.args_.get()) {
146        int my_id = -1, other_id = -1;
147        return (args_->GetAsInteger(&my_id) &&
148                other.args_->GetAsInteger(&other_id) &&
149                my_id == other_id);
150      }
151      return json_args_ == other.json_args_;
152    }
153
154    std::string Debug() {
155      return base::StringPrintf("Event(%p, %s, %s, %f)",
156                                profile_,
157                                event_name_.c_str(),
158                                json_args_.c_str(),
159                                caught_.ToJsTime());
160    }
161
162   private:
163    Profile* profile_;
164    std::string event_name_;
165    std::string json_args_;
166    scoped_ptr<base::Value> args_;
167    base::Time caught_;
168
169    DISALLOW_COPY_AND_ASSIGN(Event);
170  };
171
172  typedef ExtensionDownloadsEventRouter::DownloadsNotificationSource
173    DownloadsNotificationSource;
174
175  virtual void Observe(int type,
176                       const content::NotificationSource& source,
177                       const content::NotificationDetails& details) OVERRIDE {
178    switch (type) {
179      case chrome::NOTIFICATION_EXTENSION_DOWNLOADS_EVENT:
180        {
181          DownloadsNotificationSource* dns =
182              content::Source<DownloadsNotificationSource>(source).ptr();
183          Event* new_event = new Event(
184              dns->profile,
185              dns->event_name,
186              *content::Details<std::string>(details).ptr(), base::Time::Now());
187          events_.push_back(new_event);
188          if (waiting_ &&
189              waiting_for_.get() &&
190              new_event->Satisfies(*waiting_for_)) {
191            waiting_ = false;
192            base::MessageLoopForUI::current()->Quit();
193          }
194          break;
195        }
196      default:
197        NOTREACHED();
198    }
199  }
200
201  bool WaitFor(Profile* profile,
202               const std::string& event_name,
203               const std::string& json_args) {
204    waiting_for_.reset(new Event(profile, event_name, json_args, base::Time()));
205    for (std::deque<Event*>::const_iterator iter = events_.begin();
206         iter != events_.end(); ++iter) {
207      if ((*iter)->Satisfies(*waiting_for_.get())) {
208        return true;
209      }
210    }
211    waiting_ = true;
212    content::RunMessageLoop();
213    bool success = !waiting_;
214    if (waiting_) {
215      // Print the events that were caught since the last WaitFor() call to help
216      // find the erroneous event.
217      // TODO(benjhayden) Fuzzy-match and highlight the erroneous event.
218      for (std::deque<Event*>::const_iterator iter = events_.begin();
219          iter != events_.end(); ++iter) {
220        if ((*iter)->caught() > last_wait_) {
221          LOG(INFO) << "Caught " << (*iter)->Debug();
222        }
223      }
224      if (waiting_for_.get()) {
225        LOG(INFO) << "Timed out waiting for " << waiting_for_->Debug();
226      }
227      waiting_ = false;
228    }
229    waiting_for_.reset();
230    last_wait_ = base::Time::Now();
231    return success;
232  }
233
234 private:
235  bool waiting_;
236  base::Time last_wait_;
237  scoped_ptr<Event> waiting_for_;
238  content::NotificationRegistrar registrar_;
239  std::deque<Event*> events_;
240
241  DISALLOW_COPY_AND_ASSIGN(DownloadsEventsListener);
242};
243
244class DownloadExtensionTest : public ExtensionApiTest {
245 public:
246  DownloadExtensionTest()
247    : extension_(NULL),
248      incognito_browser_(NULL),
249      current_browser_(NULL) {
250  }
251
252 protected:
253  // Used with CreateHistoryDownloads
254  struct HistoryDownloadInfo {
255    // Filename to use. CreateHistoryDownloads will append this filename to the
256    // temporary downloads directory specified by downloads_directory().
257    const base::FilePath::CharType*   filename;
258
259    // State for the download. Note that IN_PROGRESS downloads will be created
260    // as CANCELLED.
261    DownloadItem::DownloadState state;
262
263    // Danger type for the download. Only use DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
264    // and DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT.
265    content::DownloadDangerType danger_type;
266  };
267
268  void LoadExtension(const char* name) {
269    // Store the created Extension object so that we can attach it to
270    // ExtensionFunctions.  Also load the extension in incognito profiles for
271    // testing incognito.
272    extension_ = LoadExtensionIncognito(test_data_dir_.AppendASCII(name));
273    CHECK(extension_);
274    content::WebContents* tab = chrome::AddSelectedTabWithURL(
275        current_browser(),
276        extension_->GetResourceURL("empty.html"),
277        content::PAGE_TRANSITION_LINK);
278    extensions::ExtensionSystem::Get(current_browser()->profile())->
279      event_router()->AddEventListener(
280          extensions::event_names::kOnDownloadCreated,
281          tab->GetRenderProcessHost(),
282          GetExtensionId());
283    extensions::ExtensionSystem::Get(current_browser()->profile())->
284      event_router()->AddEventListener(
285          extensions::event_names::kOnDownloadChanged,
286          tab->GetRenderProcessHost(),
287          GetExtensionId());
288    extensions::ExtensionSystem::Get(current_browser()->profile())->
289      event_router()->AddEventListener(
290          extensions::event_names::kOnDownloadErased,
291          tab->GetRenderProcessHost(),
292          GetExtensionId());
293  }
294
295  content::RenderProcessHost* AddFilenameDeterminer() {
296    content::WebContents* tab = chrome::AddSelectedTabWithURL(
297        current_browser(),
298        extension_->GetResourceURL("empty.html"),
299        content::PAGE_TRANSITION_LINK);
300    extensions::ExtensionSystem::Get(current_browser()->profile())->
301      event_router()->AddEventListener(
302          extensions::event_names::kOnDownloadDeterminingFilename,
303          tab->GetRenderProcessHost(),
304          GetExtensionId());
305    return tab->GetRenderProcessHost();
306  }
307
308  void RemoveFilenameDeterminer(content::RenderProcessHost* host) {
309    extensions::ExtensionSystem::Get(current_browser()->profile())->
310      event_router()->RemoveEventListener(
311          extensions::event_names::kOnDownloadDeterminingFilename,
312          host,
313          GetExtensionId());
314  }
315
316  Browser* current_browser() { return current_browser_; }
317
318  // InProcessBrowserTest
319  virtual void SetUpOnMainThread() OVERRIDE {
320    ExtensionApiTest::SetUpOnMainThread();
321    BrowserThread::PostTask(
322        BrowserThread::IO, FROM_HERE,
323        base::Bind(&chrome_browser_net::SetUrlRequestMocksEnabled, true));
324    InProcessBrowserTest::SetUpOnMainThread();
325    GoOnTheRecord();
326    CreateAndSetDownloadsDirectory();
327    current_browser()->profile()->GetPrefs()->SetBoolean(
328        prefs::kPromptForDownload, false);
329    GetOnRecordManager()->RemoveAllDownloads();
330    events_listener_.reset(new DownloadsEventsListener());
331    // Disable file chooser for current profile.
332    DownloadTestFileActivityObserver observer(current_browser()->profile());
333    observer.EnableFileChooser(false);
334  }
335
336  void GoOnTheRecord() { current_browser_ = browser(); }
337
338  void GoOffTheRecord() {
339    if (!incognito_browser_) {
340      incognito_browser_ = CreateIncognitoBrowser();
341      GetOffRecordManager()->RemoveAllDownloads();
342      // Disable file chooser for incognito profile.
343      DownloadTestFileActivityObserver observer(incognito_browser_->profile());
344      observer.EnableFileChooser(false);
345    }
346    current_browser_ = incognito_browser_;
347  }
348
349  bool WaitFor(const std::string& event_name, const std::string& json_args) {
350    return events_listener_->WaitFor(
351        current_browser()->profile(), event_name, json_args);
352  }
353
354  bool WaitForInterruption(
355      DownloadItem* item,
356      content::DownloadInterruptReason expected_error,
357      const std::string& on_created_event) {
358    if (!WaitFor(events::kOnDownloadCreated, on_created_event))
359      return false;
360    // Now, onCreated is always fired before interruption.
361    return WaitFor(events::kOnDownloadChanged,
362        base::StringPrintf("[{\"id\": %d,"
363                           "  \"error\": {\"current\": \"%s\"},"
364                           "  \"state\": {"
365                           "    \"previous\": \"in_progress\","
366                           "    \"current\": \"interrupted\"}}]",
367                           item->GetId(),
368                           content::InterruptReasonDebugString(
369                             expected_error).c_str()));
370  }
371
372  void ClearEvents() {
373    events_listener_->ClearEvents();
374  }
375
376  std::string GetExtensionURL() {
377    return extension_->url().spec();
378  }
379  std::string GetExtensionId() {
380    return extension_->id();
381  }
382
383  std::string GetFilename(const char* path) {
384    std::string result =
385      downloads_directory_.path().AppendASCII(path).AsUTF8Unsafe();
386#if defined(OS_WIN)
387    for (std::string::size_type next = result.find("\\");
388         next != std::string::npos;
389         next = result.find("\\", next)) {
390      result.replace(next, 1, "\\\\");
391      next += 2;
392    }
393#endif
394    return result;
395  }
396
397  DownloadManager* GetOnRecordManager() {
398    return BrowserContext::GetDownloadManager(browser()->profile());
399  }
400  DownloadManager* GetOffRecordManager() {
401    return BrowserContext::GetDownloadManager(
402        browser()->profile()->GetOffTheRecordProfile());
403  }
404  DownloadManager* GetCurrentManager() {
405    return (current_browser_ == incognito_browser_) ?
406      GetOffRecordManager() : GetOnRecordManager();
407  }
408
409  // Creates a set of history downloads based on the provided |history_info|
410  // array. |count| is the number of elements in |history_info|. On success,
411  // |items| will contain |count| DownloadItems in the order that they were
412  // specified in |history_info|. Returns true on success and false otherwise.
413  bool CreateHistoryDownloads(const HistoryDownloadInfo* history_info,
414                              size_t count,
415                              DownloadManager::DownloadVector* items) {
416    DownloadIdComparator download_id_comparator;
417    base::Time current = base::Time::Now();
418    items->clear();
419    GetOnRecordManager()->GetAllDownloads(items);
420    CHECK_EQ(0, static_cast<int>(items->size()));
421    std::vector<GURL> url_chain;
422    url_chain.push_back(GURL());
423    for (size_t i = 0; i < count; ++i) {
424      DownloadItem* item = GetOnRecordManager()->CreateDownloadItem(
425          content::DownloadItem::kInvalidId + 1 + i,
426          downloads_directory().Append(history_info[i].filename),
427          downloads_directory().Append(history_info[i].filename),
428          url_chain, GURL(),    // URL Chain, referrer
429          current, current,  // start_time, end_time
430          std::string(), std::string(), // etag, last_modified
431          1, 1,              // received_bytes, total_bytes
432          history_info[i].state,  // state
433          content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
434          content::DOWNLOAD_INTERRUPT_REASON_NONE,
435          false);                 // opened
436      items->push_back(item);
437    }
438
439    // Order by ID so that they are in the order that we created them.
440    std::sort(items->begin(), items->end(), download_id_comparator);
441    // Set the danger type if necessary.
442    for (size_t i = 0; i < count; ++i) {
443      if (history_info[i].danger_type !=
444          content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS) {
445        EXPECT_EQ(content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT,
446                  history_info[i].danger_type);
447        items->at(i)->OnContentCheckCompleted(history_info[i].danger_type);
448      }
449    }
450    return true;
451  }
452
453  void CreateSlowTestDownloads(
454      size_t count, DownloadManager::DownloadVector* items) {
455    for (size_t i = 0; i < count; ++i) {
456      scoped_ptr<content::DownloadTestObserver> observer(
457          CreateInProgressDownloadObserver(1));
458      GURL slow_download_url(URLRequestSlowDownloadJob::kUnknownSizeUrl);
459      ui_test_utils::NavigateToURLWithDisposition(
460          current_browser(), slow_download_url, CURRENT_TAB,
461          ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
462      observer->WaitForFinished();
463      EXPECT_EQ(
464          1u, observer->NumDownloadsSeenInState(DownloadItem::IN_PROGRESS));
465    }
466    GetCurrentManager()->GetAllDownloads(items);
467    ASSERT_EQ(count, items->size());
468  }
469
470  DownloadItem* CreateSlowTestDownload() {
471    scoped_ptr<content::DownloadTestObserver> observer(
472        CreateInProgressDownloadObserver(1));
473    GURL slow_download_url(URLRequestSlowDownloadJob::kUnknownSizeUrl);
474    DownloadManager* manager = GetCurrentManager();
475
476    EXPECT_EQ(0, manager->InProgressCount());
477    if (manager->InProgressCount() != 0)
478      return NULL;
479
480    ui_test_utils::NavigateToURLWithDisposition(
481        current_browser(), slow_download_url, CURRENT_TAB,
482        ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
483
484    observer->WaitForFinished();
485    EXPECT_EQ(1u, observer->NumDownloadsSeenInState(DownloadItem::IN_PROGRESS));
486
487    DownloadManager::DownloadVector items;
488    manager->GetAllDownloads(&items);
489
490    DownloadItem* new_item = NULL;
491    for (DownloadManager::DownloadVector::iterator iter = items.begin();
492         iter != items.end(); ++iter) {
493      if ((*iter)->GetState() == DownloadItem::IN_PROGRESS) {
494        // There should be only one IN_PROGRESS item.
495        EXPECT_EQ(NULL, new_item);
496        new_item = *iter;
497      }
498    }
499    return new_item;
500  }
501
502  void FinishPendingSlowDownloads() {
503    scoped_ptr<content::DownloadTestObserver> observer(
504        CreateDownloadObserver(1));
505    GURL finish_url(URLRequestSlowDownloadJob::kFinishDownloadUrl);
506    ui_test_utils::NavigateToURLWithDisposition(
507        current_browser(), finish_url, NEW_FOREGROUND_TAB,
508        ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
509    observer->WaitForFinished();
510    EXPECT_EQ(1u, observer->NumDownloadsSeenInState(DownloadItem::COMPLETE));
511  }
512
513  content::DownloadTestObserver* CreateDownloadObserver(size_t download_count) {
514    return new content::DownloadTestObserverTerminal(
515        GetCurrentManager(), download_count,
516        content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL);
517  }
518
519  content::DownloadTestObserver* CreateInProgressDownloadObserver(
520      size_t download_count) {
521    return new content::DownloadTestObserverInProgress(
522        GetCurrentManager(), download_count);
523  }
524
525  bool RunFunction(UIThreadExtensionFunction* function,
526                   const std::string& args) {
527    scoped_refptr<UIThreadExtensionFunction> delete_function(function);
528    SetUpExtensionFunction(function);
529    bool result = extension_function_test_utils::RunFunction(
530        function, args, browser(), GetFlags());
531    if (!result) {
532      LOG(ERROR) << function->GetError();
533    }
534    return result;
535  }
536
537  extension_function_test_utils::RunFunctionFlags GetFlags() {
538    return current_browser()->profile()->IsOffTheRecord() ?
539           extension_function_test_utils::INCLUDE_INCOGNITO :
540           extension_function_test_utils::NONE;
541  }
542
543  // extension_function_test_utils::RunFunction*() only uses browser for its
544  // profile(), so pass it the on-record browser so that it always uses the
545  // on-record profile to match real-life behavior.
546
547  base::Value* RunFunctionAndReturnResult(
548      scoped_refptr<UIThreadExtensionFunction> function,
549      const std::string& args) {
550    SetUpExtensionFunction(function.get());
551    return extension_function_test_utils::RunFunctionAndReturnSingleResult(
552        function.get(), args, browser(), GetFlags());
553  }
554
555  std::string RunFunctionAndReturnError(
556      scoped_refptr<UIThreadExtensionFunction> function,
557      const std::string& args) {
558    SetUpExtensionFunction(function.get());
559    return extension_function_test_utils::RunFunctionAndReturnError(
560        function.get(), args, browser(), GetFlags());
561  }
562
563  bool RunFunctionAndReturnString(
564      scoped_refptr<UIThreadExtensionFunction> function,
565      const std::string& args,
566      std::string* result_string) {
567    SetUpExtensionFunction(function.get());
568    scoped_ptr<base::Value> result(RunFunctionAndReturnResult(function, args));
569    EXPECT_TRUE(result.get());
570    return result.get() && result->GetAsString(result_string);
571  }
572
573  std::string DownloadItemIdAsArgList(const DownloadItem* download_item) {
574    return base::StringPrintf("[%d]", download_item->GetId());
575  }
576
577  const base::FilePath& downloads_directory() {
578    return downloads_directory_.path();
579  }
580
581  DownloadsEventsListener* events_listener() { return events_listener_.get(); }
582
583 private:
584  void SetUpExtensionFunction(UIThreadExtensionFunction* function) {
585    if (extension_) {
586      // Recreate the tab each time for insulation.
587      content::WebContents* tab = chrome::AddSelectedTabWithURL(
588          current_browser(),
589          extension_->GetResourceURL("empty.html"),
590          content::PAGE_TRANSITION_LINK);
591      function->set_extension(extension_);
592      function->SetRenderViewHost(tab->GetRenderViewHost());
593    }
594  }
595
596  void CreateAndSetDownloadsDirectory() {
597    ASSERT_TRUE(downloads_directory_.CreateUniqueTempDir());
598    current_browser()->profile()->GetPrefs()->SetFilePath(
599        prefs::kDownloadDefaultDirectory,
600        downloads_directory_.path());
601  }
602
603  base::ScopedTempDir downloads_directory_;
604  const extensions::Extension* extension_;
605  Browser* incognito_browser_;
606  Browser* current_browser_;
607  scoped_ptr<DownloadsEventsListener> events_listener_;
608
609  DISALLOW_COPY_AND_ASSIGN(DownloadExtensionTest);
610};
611
612class MockIconExtractorImpl : public DownloadFileIconExtractor {
613 public:
614  MockIconExtractorImpl(const base::FilePath& path,
615                        IconLoader::IconSize icon_size,
616                        const std::string& response)
617      : expected_path_(path),
618        expected_icon_size_(icon_size),
619        response_(response) {
620  }
621  virtual ~MockIconExtractorImpl() {}
622
623  virtual bool ExtractIconURLForPath(const base::FilePath& path,
624                                     IconLoader::IconSize icon_size,
625                                     IconURLCallback callback) OVERRIDE {
626    EXPECT_STREQ(expected_path_.value().c_str(), path.value().c_str());
627    EXPECT_EQ(expected_icon_size_, icon_size);
628    if (expected_path_ == path &&
629        expected_icon_size_ == icon_size) {
630      callback_ = callback;
631      BrowserThread::PostTask(
632          BrowserThread::UI, FROM_HERE,
633          base::Bind(&MockIconExtractorImpl::RunCallback,
634                     base::Unretained(this)));
635      return true;
636    } else {
637      return false;
638    }
639  }
640
641 private:
642  void RunCallback() {
643    callback_.Run(response_);
644  }
645
646  base::FilePath             expected_path_;
647  IconLoader::IconSize expected_icon_size_;
648  std::string          response_;
649  IconURLCallback      callback_;
650};
651
652bool ItemNotInProgress(DownloadItem* item) {
653  return item->GetState() != DownloadItem::IN_PROGRESS;
654}
655
656// Cancels the underlying DownloadItem when the ScopedCancellingItem goes out of
657// scope. Like a scoped_ptr, but for DownloadItems.
658class ScopedCancellingItem {
659 public:
660  explicit ScopedCancellingItem(DownloadItem* item) : item_(item) {}
661  ~ScopedCancellingItem() {
662    item_->Cancel(true);
663    content::DownloadUpdatedObserver observer(
664        item_, base::Bind(&ItemNotInProgress));
665    observer.WaitForEvent();
666  }
667  DownloadItem* get() { return item_; }
668 private:
669  DownloadItem* item_;
670  DISALLOW_COPY_AND_ASSIGN(ScopedCancellingItem);
671};
672
673// Cancels all the underlying DownloadItems when the ScopedItemVectorCanceller
674// goes out of scope. Generalization of ScopedCancellingItem to many
675// DownloadItems.
676class ScopedItemVectorCanceller {
677 public:
678  explicit ScopedItemVectorCanceller(DownloadManager::DownloadVector* items)
679    : items_(items) {
680  }
681  ~ScopedItemVectorCanceller() {
682    for (DownloadManager::DownloadVector::const_iterator item = items_->begin();
683         item != items_->end(); ++item) {
684      if ((*item)->GetState() == DownloadItem::IN_PROGRESS)
685        (*item)->Cancel(true);
686      content::DownloadUpdatedObserver observer(
687          (*item), base::Bind(&ItemNotInProgress));
688      observer.WaitForEvent();
689    }
690  }
691
692 private:
693  DownloadManager::DownloadVector* items_;
694  DISALLOW_COPY_AND_ASSIGN(ScopedItemVectorCanceller);
695};
696
697// Writes an HTML5 file so that it can be downloaded.
698class HTML5FileWriter {
699 public:
700  static bool CreateFileForTesting(fileapi::FileSystemContext* context,
701                                   const fileapi::FileSystemURL& path,
702                                   const char*data,
703                                   int length) {
704    // Create a temp file.
705    base::FilePath temp_file;
706    if (!file_util::CreateTemporaryFile(&temp_file) ||
707        file_util::WriteFile(temp_file, data, length) != length) {
708      return false;
709    }
710    // Invoke the fileapi to copy it into the sandboxed filesystem.
711    bool result = false;
712    base::WaitableEvent done_event(true, false);
713    BrowserThread::PostTask(
714        BrowserThread::IO, FROM_HERE,
715        base::Bind(&CreateFileForTestingOnIOThread,
716                   base::Unretained(context),
717                   path, temp_file,
718                   base::Unretained(&result),
719                   base::Unretained(&done_event)));
720    // Wait for that to finish.
721    done_event.Wait();
722    base::DeleteFile(temp_file, false);
723    return result;
724  }
725
726 private:
727  static void CopyInCompletion(bool* result,
728                               base::WaitableEvent* done_event,
729                               base::PlatformFileError error) {
730    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
731    *result = error == base::PLATFORM_FILE_OK;
732    done_event->Signal();
733  }
734
735  static void CreateFileForTestingOnIOThread(
736      fileapi::FileSystemContext* context,
737      const fileapi::FileSystemURL& path,
738      const base::FilePath& temp_file,
739      bool* result,
740      base::WaitableEvent* done_event) {
741    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
742    context->operation_runner()->CopyInForeignFile(
743        temp_file, path,
744        base::Bind(&CopyInCompletion,
745                   base::Unretained(result),
746                   base::Unretained(done_event)));
747  }
748};
749
750// TODO(benjhayden) Merge this with the other TestObservers.
751class JustInProgressDownloadObserver
752    : public content::DownloadTestObserverInProgress {
753 public:
754  JustInProgressDownloadObserver(
755      DownloadManager* download_manager, size_t wait_count)
756      : content::DownloadTestObserverInProgress(download_manager, wait_count) {
757  }
758
759  virtual ~JustInProgressDownloadObserver() {}
760
761 private:
762  virtual bool IsDownloadInFinalState(DownloadItem* item) OVERRIDE {
763    return item->GetState() == DownloadItem::IN_PROGRESS;
764  }
765
766  DISALLOW_COPY_AND_ASSIGN(JustInProgressDownloadObserver);
767};
768
769bool ItemIsInterrupted(DownloadItem* item) {
770  return item->GetState() == DownloadItem::INTERRUPTED;
771}
772
773content::DownloadInterruptReason InterruptReasonExtensionToContent(
774    api::InterruptReason error) {
775  switch (error) {
776    case api::INTERRUPT_REASON_NONE:
777      return content::DOWNLOAD_INTERRUPT_REASON_NONE;
778#define INTERRUPT_REASON(name, value) \
779    case api::INTERRUPT_REASON_##name: \
780      return content::DOWNLOAD_INTERRUPT_REASON_##name;
781#include "content/public/browser/download_interrupt_reason_values.h"
782#undef INTERRUPT_REASON
783  }
784  NOTREACHED();
785  return content::DOWNLOAD_INTERRUPT_REASON_NONE;
786}
787
788api::InterruptReason InterruptReasonContentToExtension(
789    content::DownloadInterruptReason error) {
790  switch (error) {
791    case content::DOWNLOAD_INTERRUPT_REASON_NONE:
792      return api::INTERRUPT_REASON_NONE;
793#define INTERRUPT_REASON(name, value) \
794    case content::DOWNLOAD_INTERRUPT_REASON_##name: \
795      return api::INTERRUPT_REASON_##name;
796#include "content/public/browser/download_interrupt_reason_values.h"
797#undef INTERRUPT_REASON
798  }
799  NOTREACHED();
800  return api::INTERRUPT_REASON_NONE;
801}
802
803}  // namespace
804
805IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
806                       DownloadExtensionTest_Open) {
807  LoadExtension("downloads_split");
808  EXPECT_STREQ(errors::kInvalidId,
809               RunFunctionAndReturnError(
810                   new DownloadsOpenFunction(),
811                   "[-42]").c_str());
812
813  DownloadItem* download_item = CreateSlowTestDownload();
814  ASSERT_TRUE(download_item);
815  EXPECT_FALSE(download_item->GetOpened());
816  EXPECT_FALSE(download_item->GetOpenWhenComplete());
817  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
818      base::StringPrintf("[{\"danger\": \"safe\","
819                         "  \"incognito\": false,"
820                         "  \"mime\": \"application/octet-stream\","
821                         "  \"paused\": false,"
822                         "  \"url\": \"%s\"}]",
823                         download_item->GetURL().spec().c_str())));
824  EXPECT_STREQ(errors::kNotComplete,
825               RunFunctionAndReturnError(
826                   new DownloadsOpenFunction(),
827                   DownloadItemIdAsArgList(download_item)).c_str());
828
829  FinishPendingSlowDownloads();
830  EXPECT_FALSE(download_item->GetOpened());
831  EXPECT_TRUE(RunFunction(new DownloadsOpenFunction(),
832                          DownloadItemIdAsArgList(download_item)));
833  EXPECT_TRUE(download_item->GetOpened());
834}
835
836IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
837                       DownloadExtensionTest_PauseResumeCancelErase) {
838  DownloadItem* download_item = CreateSlowTestDownload();
839  ASSERT_TRUE(download_item);
840
841  // Call pause().  It should succeed and the download should be paused on
842  // return.
843  EXPECT_TRUE(RunFunction(new DownloadsPauseFunction(),
844                          DownloadItemIdAsArgList(download_item)));
845  EXPECT_TRUE(download_item->IsPaused());
846
847  // Calling pause() twice shouldn't be an error.
848  EXPECT_TRUE(RunFunction(new DownloadsPauseFunction(),
849                          DownloadItemIdAsArgList(download_item)));
850  EXPECT_TRUE(download_item->IsPaused());
851
852  // Now try resuming this download.  It should succeed.
853  EXPECT_TRUE(RunFunction(new DownloadsResumeFunction(),
854                          DownloadItemIdAsArgList(download_item)));
855  EXPECT_FALSE(download_item->IsPaused());
856
857  // Resume again.  Resuming a download that wasn't paused is not an error.
858  EXPECT_TRUE(RunFunction(new DownloadsResumeFunction(),
859                          DownloadItemIdAsArgList(download_item)));
860  EXPECT_FALSE(download_item->IsPaused());
861
862  // Pause again.
863  EXPECT_TRUE(RunFunction(new DownloadsPauseFunction(),
864                          DownloadItemIdAsArgList(download_item)));
865  EXPECT_TRUE(download_item->IsPaused());
866
867  // And now cancel.
868  EXPECT_TRUE(RunFunction(new DownloadsCancelFunction(),
869                          DownloadItemIdAsArgList(download_item)));
870  EXPECT_EQ(DownloadItem::CANCELLED, download_item->GetState());
871
872  // Cancel again.  Shouldn't have any effect.
873  EXPECT_TRUE(RunFunction(new DownloadsCancelFunction(),
874                          DownloadItemIdAsArgList(download_item)));
875  EXPECT_EQ(DownloadItem::CANCELLED, download_item->GetState());
876
877  // Calling paused on a non-active download yields kInvalidId.
878  std::string error = RunFunctionAndReturnError(
879      new DownloadsPauseFunction(), DownloadItemIdAsArgList(download_item));
880  EXPECT_STREQ(errors::kNotInProgress, error.c_str());
881
882  // Calling resume on a non-active download yields kInvalidId
883  error = RunFunctionAndReturnError(
884      new DownloadsResumeFunction(), DownloadItemIdAsArgList(download_item));
885  EXPECT_STREQ(errors::kNotResumable, error.c_str());
886
887  // Calling paused on a non-existent download yields kInvalidId.
888  error = RunFunctionAndReturnError(
889      new DownloadsPauseFunction(), "[-42]");
890  EXPECT_STREQ(errors::kInvalidId, error.c_str());
891
892  // Calling resume on a non-existent download yields kInvalidId
893  error = RunFunctionAndReturnError(
894      new DownloadsResumeFunction(), "[-42]");
895  EXPECT_STREQ(errors::kInvalidId, error.c_str());
896
897  int id = download_item->GetId();
898  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
899      new DownloadsEraseFunction(),
900      base::StringPrintf("[{\"id\": %d}]", id)));
901  DownloadManager::DownloadVector items;
902  GetCurrentManager()->GetAllDownloads(&items);
903  EXPECT_EQ(0UL, items.size());
904  ASSERT_TRUE(result);
905  download_item = NULL;
906  base::ListValue* result_list = NULL;
907  ASSERT_TRUE(result->GetAsList(&result_list));
908  ASSERT_EQ(1UL, result_list->GetSize());
909  int element = -1;
910  ASSERT_TRUE(result_list->GetInteger(0, &element));
911  EXPECT_EQ(id, element);
912}
913
914scoped_refptr<UIThreadExtensionFunction> MockedGetFileIconFunction(
915    const base::FilePath& expected_path,
916    IconLoader::IconSize icon_size,
917    const std::string& response) {
918  scoped_refptr<DownloadsGetFileIconFunction> function(
919      new DownloadsGetFileIconFunction());
920  function->SetIconExtractorForTesting(new MockIconExtractorImpl(
921      expected_path, icon_size, response));
922  return function;
923}
924
925// Test downloads.getFileIcon() on in-progress, finished, cancelled and deleted
926// download items.
927IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
928    DownloadExtensionTest_FileIcon_Active) {
929  DownloadItem* download_item = CreateSlowTestDownload();
930  ASSERT_TRUE(download_item);
931  ASSERT_FALSE(download_item->GetTargetFilePath().empty());
932  std::string args32(base::StringPrintf("[%d, {\"size\": 32}]",
933                     download_item->GetId()));
934  std::string result_string;
935
936  // Get the icon for the in-progress download.  This call should succeed even
937  // if the file type isn't registered.
938  // Test whether the correct path is being pased into the icon extractor.
939  EXPECT_TRUE(RunFunctionAndReturnString(MockedGetFileIconFunction(
940          download_item->GetTargetFilePath(), IconLoader::NORMAL, "foo"),
941      base::StringPrintf("[%d, {}]", download_item->GetId()), &result_string));
942
943  // Now try a 16x16 icon.
944  EXPECT_TRUE(RunFunctionAndReturnString(MockedGetFileIconFunction(
945          download_item->GetTargetFilePath(), IconLoader::SMALL, "foo"),
946      base::StringPrintf("[%d, {\"size\": 16}]", download_item->GetId()),
947      &result_string));
948
949  // Explicitly asking for 32x32 should give us a 32x32 icon.
950  EXPECT_TRUE(RunFunctionAndReturnString(MockedGetFileIconFunction(
951          download_item->GetTargetFilePath(), IconLoader::NORMAL, "foo"),
952      args32, &result_string));
953
954  // Finish the download and try again.
955  FinishPendingSlowDownloads();
956  EXPECT_EQ(DownloadItem::COMPLETE, download_item->GetState());
957  EXPECT_TRUE(RunFunctionAndReturnString(MockedGetFileIconFunction(
958          download_item->GetTargetFilePath(), IconLoader::NORMAL, "foo"),
959      args32, &result_string));
960
961  // Check the path passed to the icon extractor post-completion.
962  EXPECT_TRUE(RunFunctionAndReturnString(MockedGetFileIconFunction(
963          download_item->GetTargetFilePath(), IconLoader::NORMAL, "foo"),
964      args32, &result_string));
965
966  // Now create another download.
967  download_item = CreateSlowTestDownload();
968  ASSERT_TRUE(download_item);
969  ASSERT_FALSE(download_item->GetTargetFilePath().empty());
970  args32 = base::StringPrintf("[%d, {\"size\": 32}]", download_item->GetId());
971
972  // Cancel the download. As long as the download has a target path, we should
973  // be able to query the file icon.
974  download_item->Cancel(true);
975  ASSERT_FALSE(download_item->GetTargetFilePath().empty());
976  // Let cleanup complete on the FILE thread.
977  content::RunAllPendingInMessageLoop(BrowserThread::FILE);
978  // Check the path passed to the icon extractor post-cancellation.
979  EXPECT_TRUE(RunFunctionAndReturnString(MockedGetFileIconFunction(
980          download_item->GetTargetFilePath(), IconLoader::NORMAL, "foo"),
981      args32,
982      &result_string));
983
984  // Simulate an error during icon load by invoking the mock with an empty
985  // result string.
986  std::string error = RunFunctionAndReturnError(
987      MockedGetFileIconFunction(download_item->GetTargetFilePath(),
988                                IconLoader::NORMAL,
989                                std::string()),
990      args32);
991  EXPECT_STREQ(errors::kIconNotFound, error.c_str());
992
993  // Once the download item is deleted, we should return kInvalidId.
994  int id = download_item->GetId();
995  download_item->Remove();
996  download_item = NULL;
997  EXPECT_EQ(static_cast<DownloadItem*>(NULL),
998            GetCurrentManager()->GetDownload(id));
999  error = RunFunctionAndReturnError(new DownloadsGetFileIconFunction(), args32);
1000  EXPECT_STREQ(errors::kInvalidId,
1001               error.c_str());
1002}
1003
1004// Test that we can acquire file icons for history downloads regardless of
1005// whether they exist or not.  If the file doesn't exist we should receive a
1006// generic icon from the OS/toolkit that may or may not be specific to the file
1007// type.
1008IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
1009    DownloadExtensionTest_FileIcon_History) {
1010  const HistoryDownloadInfo kHistoryInfo[] = {
1011    { FILE_PATH_LITERAL("real.txt"),
1012      DownloadItem::COMPLETE,
1013      content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS },
1014    { FILE_PATH_LITERAL("fake.txt"),
1015      DownloadItem::COMPLETE,
1016      content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS }
1017  };
1018  DownloadManager::DownloadVector all_downloads;
1019  ASSERT_TRUE(CreateHistoryDownloads(kHistoryInfo, arraysize(kHistoryInfo),
1020                                     &all_downloads));
1021
1022  base::FilePath real_path = all_downloads[0]->GetTargetFilePath();
1023  base::FilePath fake_path = all_downloads[1]->GetTargetFilePath();
1024
1025  EXPECT_EQ(0, file_util::WriteFile(real_path, "", 0));
1026  ASSERT_TRUE(base::PathExists(real_path));
1027  ASSERT_FALSE(base::PathExists(fake_path));
1028
1029  for (DownloadManager::DownloadVector::iterator iter = all_downloads.begin();
1030       iter != all_downloads.end();
1031       ++iter) {
1032    std::string result_string;
1033    // Use a MockIconExtractorImpl to test if the correct path is being passed
1034    // into the DownloadFileIconExtractor.
1035    EXPECT_TRUE(RunFunctionAndReturnString(MockedGetFileIconFunction(
1036            (*iter)->GetTargetFilePath(), IconLoader::NORMAL, "hello"),
1037        base::StringPrintf("[%d, {\"size\": 32}]", (*iter)->GetId()),
1038        &result_string));
1039    EXPECT_STREQ("hello", result_string.c_str());
1040  }
1041}
1042
1043// Test passing the empty query to search().
1044IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
1045                       DownloadExtensionTest_SearchEmptyQuery) {
1046  ScopedCancellingItem item(CreateSlowTestDownload());
1047  ASSERT_TRUE(item.get());
1048
1049  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
1050      new DownloadsSearchFunction(), "[{}]"));
1051  ASSERT_TRUE(result.get());
1052  base::ListValue* result_list = NULL;
1053  ASSERT_TRUE(result->GetAsList(&result_list));
1054  ASSERT_EQ(1UL, result_list->GetSize());
1055}
1056
1057// Test the |filenameRegex| parameter for search().
1058IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
1059    DownloadExtensionTest_SearchFilenameRegex) {
1060  const HistoryDownloadInfo kHistoryInfo[] = {
1061    { FILE_PATH_LITERAL("foobar"),
1062      DownloadItem::COMPLETE,
1063      content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS },
1064    { FILE_PATH_LITERAL("baz"),
1065      DownloadItem::COMPLETE,
1066      content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS }
1067  };
1068  DownloadManager::DownloadVector all_downloads;
1069  ASSERT_TRUE(CreateHistoryDownloads(kHistoryInfo, arraysize(kHistoryInfo),
1070                                     &all_downloads));
1071
1072  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
1073      new DownloadsSearchFunction(), "[{\"filenameRegex\": \"foobar\"}]"));
1074  ASSERT_TRUE(result.get());
1075  base::ListValue* result_list = NULL;
1076  ASSERT_TRUE(result->GetAsList(&result_list));
1077  ASSERT_EQ(1UL, result_list->GetSize());
1078  base::DictionaryValue* item_value = NULL;
1079  ASSERT_TRUE(result_list->GetDictionary(0, &item_value));
1080  int item_id = -1;
1081  ASSERT_TRUE(item_value->GetInteger("id", &item_id));
1082  ASSERT_EQ(all_downloads[0]->GetId(), static_cast<uint32>(item_id));
1083}
1084
1085// Test the |id| parameter for search().
1086IN_PROC_BROWSER_TEST_F(DownloadExtensionTest, DownloadExtensionTest_SearchId) {
1087  DownloadManager::DownloadVector items;
1088  CreateSlowTestDownloads(2, &items);
1089  ScopedItemVectorCanceller delete_items(&items);
1090
1091  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
1092      new DownloadsSearchFunction(), base::StringPrintf(
1093          "[{\"id\": %u}]", items[0]->GetId())));
1094  ASSERT_TRUE(result.get());
1095  base::ListValue* result_list = NULL;
1096  ASSERT_TRUE(result->GetAsList(&result_list));
1097  ASSERT_EQ(1UL, result_list->GetSize());
1098  base::DictionaryValue* item_value = NULL;
1099  ASSERT_TRUE(result_list->GetDictionary(0, &item_value));
1100  int item_id = -1;
1101  ASSERT_TRUE(item_value->GetInteger("id", &item_id));
1102  ASSERT_EQ(items[0]->GetId(), static_cast<uint32>(item_id));
1103}
1104
1105// Test specifying both the |id| and |filename| parameters for search().
1106IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
1107    DownloadExtensionTest_SearchIdAndFilename) {
1108  DownloadManager::DownloadVector items;
1109  CreateSlowTestDownloads(2, &items);
1110  ScopedItemVectorCanceller delete_items(&items);
1111
1112  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
1113      new DownloadsSearchFunction(),
1114      "[{\"id\": 0, \"filename\": \"foobar\"}]"));
1115  ASSERT_TRUE(result.get());
1116  base::ListValue* result_list = NULL;
1117  ASSERT_TRUE(result->GetAsList(&result_list));
1118  ASSERT_EQ(0UL, result_list->GetSize());
1119}
1120
1121// Test a single |orderBy| parameter for search().
1122IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
1123    DownloadExtensionTest_SearchOrderBy) {
1124  const HistoryDownloadInfo kHistoryInfo[] = {
1125    { FILE_PATH_LITERAL("zzz"),
1126      DownloadItem::COMPLETE,
1127      content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS },
1128    { FILE_PATH_LITERAL("baz"),
1129      DownloadItem::COMPLETE,
1130      content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS }
1131  };
1132  DownloadManager::DownloadVector items;
1133  ASSERT_TRUE(CreateHistoryDownloads(kHistoryInfo, arraysize(kHistoryInfo),
1134                                     &items));
1135
1136  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
1137      new DownloadsSearchFunction(), "[{\"orderBy\": [\"filename\"]}]"));
1138  ASSERT_TRUE(result.get());
1139  base::ListValue* result_list = NULL;
1140  ASSERT_TRUE(result->GetAsList(&result_list));
1141  ASSERT_EQ(2UL, result_list->GetSize());
1142  base::DictionaryValue* item0_value = NULL;
1143  base::DictionaryValue* item1_value = NULL;
1144  ASSERT_TRUE(result_list->GetDictionary(0, &item0_value));
1145  ASSERT_TRUE(result_list->GetDictionary(1, &item1_value));
1146  std::string item0_name, item1_name;
1147  ASSERT_TRUE(item0_value->GetString("filename", &item0_name));
1148  ASSERT_TRUE(item1_value->GetString("filename", &item1_name));
1149  ASSERT_GT(items[0]->GetTargetFilePath().value(),
1150            items[1]->GetTargetFilePath().value());
1151  ASSERT_LT(item0_name, item1_name);
1152}
1153
1154// Test specifying an empty |orderBy| parameter for search().
1155IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
1156    DownloadExtensionTest_SearchOrderByEmpty) {
1157  const HistoryDownloadInfo kHistoryInfo[] = {
1158    { FILE_PATH_LITERAL("zzz"),
1159      DownloadItem::COMPLETE,
1160      content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS },
1161    { FILE_PATH_LITERAL("baz"),
1162      DownloadItem::COMPLETE,
1163      content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS }
1164  };
1165  DownloadManager::DownloadVector items;
1166  ASSERT_TRUE(CreateHistoryDownloads(kHistoryInfo, arraysize(kHistoryInfo),
1167                                     &items));
1168
1169  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
1170      new DownloadsSearchFunction(), "[{\"orderBy\": []}]"));
1171  ASSERT_TRUE(result.get());
1172  base::ListValue* result_list = NULL;
1173  ASSERT_TRUE(result->GetAsList(&result_list));
1174  ASSERT_EQ(2UL, result_list->GetSize());
1175  base::DictionaryValue* item0_value = NULL;
1176  base::DictionaryValue* item1_value = NULL;
1177  ASSERT_TRUE(result_list->GetDictionary(0, &item0_value));
1178  ASSERT_TRUE(result_list->GetDictionary(1, &item1_value));
1179  std::string item0_name, item1_name;
1180  ASSERT_TRUE(item0_value->GetString("filename", &item0_name));
1181  ASSERT_TRUE(item1_value->GetString("filename", &item1_name));
1182  ASSERT_GT(items[0]->GetTargetFilePath().value(),
1183            items[1]->GetTargetFilePath().value());
1184  ASSERT_GT(item0_name, item1_name);
1185}
1186
1187// Test the |danger| option for search().
1188IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
1189    DownloadExtensionTest_SearchDanger) {
1190  const HistoryDownloadInfo kHistoryInfo[] = {
1191    { FILE_PATH_LITERAL("zzz"),
1192      DownloadItem::COMPLETE,
1193      content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT },
1194    { FILE_PATH_LITERAL("baz"),
1195      DownloadItem::COMPLETE,
1196      content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS }
1197  };
1198  DownloadManager::DownloadVector items;
1199  ASSERT_TRUE(CreateHistoryDownloads(kHistoryInfo, arraysize(kHistoryInfo),
1200                                     &items));
1201
1202  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
1203      new DownloadsSearchFunction(), "[{\"danger\": \"content\"}]"));
1204  ASSERT_TRUE(result.get());
1205  base::ListValue* result_list = NULL;
1206  ASSERT_TRUE(result->GetAsList(&result_list));
1207  ASSERT_EQ(1UL, result_list->GetSize());
1208}
1209
1210// Test the |state| option for search().
1211IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
1212    DownloadExtensionTest_SearchState) {
1213  DownloadManager::DownloadVector items;
1214  CreateSlowTestDownloads(2, &items);
1215  ScopedItemVectorCanceller delete_items(&items);
1216
1217  items[0]->Cancel(true);
1218
1219  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
1220      new DownloadsSearchFunction(), "[{\"state\": \"in_progress\"}]"));
1221  ASSERT_TRUE(result.get());
1222  base::ListValue* result_list = NULL;
1223  ASSERT_TRUE(result->GetAsList(&result_list));
1224  ASSERT_EQ(1UL, result_list->GetSize());
1225}
1226
1227// Test the |limit| option for search().
1228IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
1229                       DownloadExtensionTest_SearchLimit) {
1230  DownloadManager::DownloadVector items;
1231  CreateSlowTestDownloads(2, &items);
1232  ScopedItemVectorCanceller delete_items(&items);
1233
1234  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
1235      new DownloadsSearchFunction(), "[{\"limit\": 1}]"));
1236  ASSERT_TRUE(result.get());
1237  base::ListValue* result_list = NULL;
1238  ASSERT_TRUE(result->GetAsList(&result_list));
1239  ASSERT_EQ(1UL, result_list->GetSize());
1240}
1241
1242// Test invalid search parameters.
1243IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
1244    DownloadExtensionTest_SearchInvalid) {
1245  std::string error = RunFunctionAndReturnError(
1246      new DownloadsSearchFunction(), "[{\"filenameRegex\": \"(\"}]");
1247  EXPECT_STREQ(errors::kInvalidFilter,
1248      error.c_str());
1249  error = RunFunctionAndReturnError(
1250      new DownloadsSearchFunction(), "[{\"orderBy\": [\"goat\"]}]");
1251  EXPECT_STREQ(errors::kInvalidOrderBy,
1252      error.c_str());
1253  error = RunFunctionAndReturnError(
1254      new DownloadsSearchFunction(), "[{\"limit\": -1}]");
1255  EXPECT_STREQ(errors::kInvalidQueryLimit,
1256      error.c_str());
1257}
1258
1259// Test searching using multiple conditions through multiple downloads.
1260IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
1261    DownloadExtensionTest_SearchPlural) {
1262  const HistoryDownloadInfo kHistoryInfo[] = {
1263    { FILE_PATH_LITERAL("aaa"),
1264      DownloadItem::CANCELLED,
1265      content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS },
1266    { FILE_PATH_LITERAL("zzz"),
1267      DownloadItem::COMPLETE,
1268      content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT },
1269    { FILE_PATH_LITERAL("baz"),
1270      DownloadItem::COMPLETE,
1271      content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT },
1272  };
1273  DownloadManager::DownloadVector items;
1274  ASSERT_TRUE(CreateHistoryDownloads(kHistoryInfo, arraysize(kHistoryInfo),
1275                                     &items));
1276
1277  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
1278      new DownloadsSearchFunction(), "[{"
1279      "\"state\": \"complete\", "
1280      "\"danger\": \"content\", "
1281      "\"orderBy\": [\"filename\"], "
1282      "\"limit\": 1}]"));
1283  ASSERT_TRUE(result.get());
1284  base::ListValue* result_list = NULL;
1285  ASSERT_TRUE(result->GetAsList(&result_list));
1286  ASSERT_EQ(1UL, result_list->GetSize());
1287  base::DictionaryValue* item_value = NULL;
1288  ASSERT_TRUE(result_list->GetDictionary(0, &item_value));
1289  base::FilePath::StringType item_name;
1290  ASSERT_TRUE(item_value->GetString("filename", &item_name));
1291  ASSERT_EQ(items[2]->GetTargetFilePath().value(), item_name);
1292}
1293
1294// Test that incognito downloads are only visible in incognito contexts, and
1295// test that on-record downloads are visible in both incognito and on-record
1296// contexts, for DownloadsSearchFunction, DownloadsPauseFunction,
1297// DownloadsResumeFunction, and DownloadsCancelFunction.
1298IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
1299    DownloadExtensionTest_SearchPauseResumeCancelGetFileIconIncognito) {
1300  scoped_ptr<base::Value> result_value;
1301  base::ListValue* result_list = NULL;
1302  base::DictionaryValue* result_dict = NULL;
1303  base::FilePath::StringType filename;
1304  bool is_incognito = false;
1305  std::string error;
1306  std::string on_item_arg;
1307  std::string off_item_arg;
1308  std::string result_string;
1309
1310  // Set up one on-record item and one off-record item.
1311  // Set up the off-record item first because otherwise there are mysteriously 3
1312  // items total instead of 2.
1313  // TODO(benjhayden): Figure out where the third item comes from.
1314  GoOffTheRecord();
1315  DownloadItem* off_item = CreateSlowTestDownload();
1316  ASSERT_TRUE(off_item);
1317  off_item_arg = DownloadItemIdAsArgList(off_item);
1318
1319  GoOnTheRecord();
1320  DownloadItem* on_item = CreateSlowTestDownload();
1321  ASSERT_TRUE(on_item);
1322  on_item_arg = DownloadItemIdAsArgList(on_item);
1323  ASSERT_TRUE(on_item->GetTargetFilePath() != off_item->GetTargetFilePath());
1324
1325  // Extensions running in the incognito window should have access to both
1326  // items because the Test extension is in spanning mode.
1327  GoOffTheRecord();
1328  result_value.reset(RunFunctionAndReturnResult(
1329      new DownloadsSearchFunction(), "[{}]"));
1330  ASSERT_TRUE(result_value.get());
1331  ASSERT_TRUE(result_value->GetAsList(&result_list));
1332  ASSERT_EQ(2UL, result_list->GetSize());
1333  ASSERT_TRUE(result_list->GetDictionary(0, &result_dict));
1334  ASSERT_TRUE(result_dict->GetString("filename", &filename));
1335  ASSERT_TRUE(result_dict->GetBoolean("incognito", &is_incognito));
1336  EXPECT_TRUE(on_item->GetTargetFilePath() == base::FilePath(filename));
1337  EXPECT_FALSE(is_incognito);
1338  ASSERT_TRUE(result_list->GetDictionary(1, &result_dict));
1339  ASSERT_TRUE(result_dict->GetString("filename", &filename));
1340  ASSERT_TRUE(result_dict->GetBoolean("incognito", &is_incognito));
1341  EXPECT_TRUE(off_item->GetTargetFilePath() == base::FilePath(filename));
1342  EXPECT_TRUE(is_incognito);
1343
1344  // Extensions running in the on-record window should have access only to the
1345  // on-record item.
1346  GoOnTheRecord();
1347  result_value.reset(RunFunctionAndReturnResult(
1348      new DownloadsSearchFunction(), "[{}]"));
1349  ASSERT_TRUE(result_value.get());
1350  ASSERT_TRUE(result_value->GetAsList(&result_list));
1351  ASSERT_EQ(1UL, result_list->GetSize());
1352  ASSERT_TRUE(result_list->GetDictionary(0, &result_dict));
1353  ASSERT_TRUE(result_dict->GetString("filename", &filename));
1354  EXPECT_TRUE(on_item->GetTargetFilePath() == base::FilePath(filename));
1355  ASSERT_TRUE(result_dict->GetBoolean("incognito", &is_incognito));
1356  EXPECT_FALSE(is_incognito);
1357
1358  // Pausing/Resuming the off-record item while on the record should return an
1359  // error. Cancelling "non-existent" downloads is not an error.
1360  error = RunFunctionAndReturnError(new DownloadsPauseFunction(), off_item_arg);
1361  EXPECT_STREQ(errors::kInvalidId,
1362               error.c_str());
1363  error = RunFunctionAndReturnError(new DownloadsResumeFunction(),
1364                                    off_item_arg);
1365  EXPECT_STREQ(errors::kInvalidId,
1366               error.c_str());
1367  error = RunFunctionAndReturnError(
1368      new DownloadsGetFileIconFunction(),
1369      base::StringPrintf("[%d, {}]", off_item->GetId()));
1370  EXPECT_STREQ(errors::kInvalidId,
1371               error.c_str());
1372
1373  GoOffTheRecord();
1374
1375  // Do the FileIcon test for both the on- and off-items while off the record.
1376  // NOTE(benjhayden): This does not include the FileIcon test from history,
1377  // just active downloads. This shouldn't be a problem.
1378  EXPECT_TRUE(RunFunctionAndReturnString(MockedGetFileIconFunction(
1379          on_item->GetTargetFilePath(), IconLoader::NORMAL, "foo"),
1380      base::StringPrintf("[%d, {}]", on_item->GetId()), &result_string));
1381  EXPECT_TRUE(RunFunctionAndReturnString(MockedGetFileIconFunction(
1382          off_item->GetTargetFilePath(), IconLoader::NORMAL, "foo"),
1383      base::StringPrintf("[%d, {}]", off_item->GetId()), &result_string));
1384
1385  // Do the pause/resume/cancel test for both the on- and off-items while off
1386  // the record.
1387  EXPECT_TRUE(RunFunction(new DownloadsPauseFunction(), on_item_arg));
1388  EXPECT_TRUE(on_item->IsPaused());
1389  EXPECT_TRUE(RunFunction(new DownloadsPauseFunction(), on_item_arg));
1390  EXPECT_TRUE(on_item->IsPaused());
1391  EXPECT_TRUE(RunFunction(new DownloadsResumeFunction(), on_item_arg));
1392  EXPECT_FALSE(on_item->IsPaused());
1393  EXPECT_TRUE(RunFunction(new DownloadsResumeFunction(), on_item_arg));
1394  EXPECT_FALSE(on_item->IsPaused());
1395  EXPECT_TRUE(RunFunction(new DownloadsPauseFunction(), on_item_arg));
1396  EXPECT_TRUE(on_item->IsPaused());
1397  EXPECT_TRUE(RunFunction(new DownloadsCancelFunction(), on_item_arg));
1398  EXPECT_EQ(DownloadItem::CANCELLED, on_item->GetState());
1399  EXPECT_TRUE(RunFunction(new DownloadsCancelFunction(), on_item_arg));
1400  EXPECT_EQ(DownloadItem::CANCELLED, on_item->GetState());
1401  error = RunFunctionAndReturnError(new DownloadsPauseFunction(), on_item_arg);
1402  EXPECT_STREQ(errors::kNotInProgress, error.c_str());
1403  error = RunFunctionAndReturnError(new DownloadsResumeFunction(), on_item_arg);
1404  EXPECT_STREQ(errors::kNotResumable, error.c_str());
1405  EXPECT_TRUE(RunFunction(new DownloadsPauseFunction(), off_item_arg));
1406  EXPECT_TRUE(off_item->IsPaused());
1407  EXPECT_TRUE(RunFunction(new DownloadsPauseFunction(), off_item_arg));
1408  EXPECT_TRUE(off_item->IsPaused());
1409  EXPECT_TRUE(RunFunction(new DownloadsResumeFunction(), off_item_arg));
1410  EXPECT_FALSE(off_item->IsPaused());
1411  EXPECT_TRUE(RunFunction(new DownloadsResumeFunction(), off_item_arg));
1412  EXPECT_FALSE(off_item->IsPaused());
1413  EXPECT_TRUE(RunFunction(new DownloadsPauseFunction(), off_item_arg));
1414  EXPECT_TRUE(off_item->IsPaused());
1415  EXPECT_TRUE(RunFunction(new DownloadsCancelFunction(), off_item_arg));
1416  EXPECT_EQ(DownloadItem::CANCELLED, off_item->GetState());
1417  EXPECT_TRUE(RunFunction(new DownloadsCancelFunction(), off_item_arg));
1418  EXPECT_EQ(DownloadItem::CANCELLED, off_item->GetState());
1419  error = RunFunctionAndReturnError(new DownloadsPauseFunction(), off_item_arg);
1420  EXPECT_STREQ(errors::kNotInProgress, error.c_str());
1421  error = RunFunctionAndReturnError(new DownloadsResumeFunction(),
1422                                    off_item_arg);
1423  EXPECT_STREQ(errors::kNotResumable, error.c_str());
1424}
1425
1426// Test that we can start a download and that the correct sequence of events is
1427// fired for it.
1428IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
1429                       DownloadExtensionTest_Download_Basic) {
1430  LoadExtension("downloads_split");
1431  ASSERT_TRUE(StartEmbeddedTestServer());
1432  ASSERT_TRUE(test_server()->Start());
1433  std::string download_url = test_server()->GetURL("slow?0").spec();
1434  GoOnTheRecord();
1435
1436  // Start downloading a file.
1437  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
1438      new DownloadsDownloadFunction(), base::StringPrintf(
1439          "[{\"url\": \"%s\"}]", download_url.c_str())));
1440  ASSERT_TRUE(result.get());
1441  int result_id = -1;
1442  ASSERT_TRUE(result->GetAsInteger(&result_id));
1443  DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
1444  ASSERT_TRUE(item);
1445  ScopedCancellingItem canceller(item);
1446  ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
1447
1448  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
1449      base::StringPrintf("[{\"danger\": \"safe\","
1450                         "  \"incognito\": false,"
1451                         "  \"mime\": \"text/plain\","
1452                         "  \"paused\": false,"
1453                         "  \"url\": \"%s\"}]",
1454                         download_url.c_str())));
1455  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
1456      base::StringPrintf("[{\"id\": %d,"
1457                         "  \"filename\": {"
1458                         "    \"previous\": \"\","
1459                         "    \"current\": \"%s\"}}]",
1460                         result_id,
1461                         GetFilename("slow.txt").c_str())));
1462  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
1463      base::StringPrintf("[{\"id\": %d,"
1464                         "  \"state\": {"
1465                         "    \"previous\": \"in_progress\","
1466                         "    \"current\": \"complete\"}}]",
1467                         result_id)));
1468}
1469
1470// Test that we can start a download from an incognito context, and that the
1471// download knows that it's incognito.
1472IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
1473                       DownloadExtensionTest_Download_Incognito) {
1474  LoadExtension("downloads_split");
1475  ASSERT_TRUE(StartEmbeddedTestServer());
1476  ASSERT_TRUE(test_server()->Start());
1477  GoOffTheRecord();
1478  std::string download_url = test_server()->GetURL("slow?0").spec();
1479
1480  // Start downloading a file.
1481  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
1482      new DownloadsDownloadFunction(), base::StringPrintf(
1483          "[{\"url\": \"%s\"}]", download_url.c_str())));
1484  ASSERT_TRUE(result.get());
1485  int result_id = -1;
1486  ASSERT_TRUE(result->GetAsInteger(&result_id));
1487  DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
1488  ASSERT_TRUE(item);
1489  ScopedCancellingItem canceller(item);
1490  ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
1491
1492  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
1493      base::StringPrintf("[{\"danger\": \"safe\","
1494                         "  \"incognito\": true,"
1495                         "  \"mime\": \"text/plain\","
1496                         "  \"paused\": false,"
1497                         "  \"url\": \"%s\"}]",
1498                         download_url.c_str())));
1499  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
1500      base::StringPrintf("[{\"id\":%d,"
1501                         "  \"filename\": {"
1502                         "    \"previous\": \"\","
1503                         "    \"current\": \"%s\"}}]",
1504                         result_id,
1505                         GetFilename("slow.txt").c_str())));
1506  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
1507      base::StringPrintf("[{\"id\":%d,"
1508                         "  \"state\": {"
1509                         "    \"current\": \"complete\","
1510                         "    \"previous\": \"in_progress\"}}]",
1511                         result_id)));
1512}
1513
1514#if defined(OS_WIN) && defined(USE_AURA)
1515// This test is very flaky on Win Aura. http://crbug.com/248438
1516#define MAYBE_DownloadExtensionTest_Download_UnsafeHeaders \
1517    DISABLED_DownloadExtensionTest_Download_UnsafeHeaders
1518#else
1519#define MAYBE_DownloadExtensionTest_Download_UnsafeHeaders \
1520    DownloadExtensionTest_Download_UnsafeHeaders
1521#endif
1522
1523// Test that we disallow certain headers case-insensitively.
1524IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
1525                       MAYBE_DownloadExtensionTest_Download_UnsafeHeaders) {
1526  LoadExtension("downloads_split");
1527  ASSERT_TRUE(StartEmbeddedTestServer());
1528  ASSERT_TRUE(test_server()->Start());
1529  GoOnTheRecord();
1530
1531  static const char* kUnsafeHeaders[] = {
1532    "Accept-chArsEt",
1533    "accept-eNcoding",
1534    "coNNection",
1535    "coNteNt-leNgth",
1536    "cooKIE",
1537    "cOOkie2",
1538    "coNteNt-traNsfer-eNcodiNg",
1539    "dAtE",
1540    "ExpEcT",
1541    "hOsT",
1542    "kEEp-aLivE",
1543    "rEfErEr",
1544    "tE",
1545    "trAilER",
1546    "trANsfer-eNcodiNg",
1547    "upGRAde",
1548    "usER-agENt",
1549    "viA",
1550    "pRoxY-",
1551    "sEc-",
1552    "pRoxY-probably-not-evil",
1553    "sEc-probably-not-evil",
1554    "oRiGiN",
1555    "Access-Control-Request-Headers",
1556    "Access-Control-Request-Method",
1557  };
1558
1559  for (size_t index = 0; index < arraysize(kUnsafeHeaders); ++index) {
1560    std::string download_url = test_server()->GetURL("slow?0").spec();
1561    EXPECT_STREQ(errors::kInvalidHeader,
1562                  RunFunctionAndReturnError(new DownloadsDownloadFunction(),
1563                                            base::StringPrintf(
1564        "[{\"url\": \"%s\","
1565        "  \"filename\": \"unsafe-header-%d.txt\","
1566        "  \"headers\": [{"
1567        "    \"name\": \"%s\","
1568        "    \"value\": \"unsafe\"}]}]",
1569        download_url.c_str(),
1570        static_cast<int>(index),
1571        kUnsafeHeaders[index])).c_str());
1572  }
1573}
1574
1575#if defined(OS_WIN)
1576#define MAYBE_DownloadExtensionTest_Download_Subdirectory\
1577        DISABLED_DownloadExtensionTest_Download_Subdirectory
1578#else
1579#define MAYBE_DownloadExtensionTest_Download_Subdirectory\
1580        DownloadExtensionTest_Download_Subdirectory
1581#endif
1582IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
1583                       MAYBE_DownloadExtensionTest_Download_Subdirectory) {
1584  LoadExtension("downloads_split");
1585  ASSERT_TRUE(StartEmbeddedTestServer());
1586  ASSERT_TRUE(test_server()->Start());
1587  std::string download_url = test_server()->GetURL("slow?0").spec();
1588  GoOnTheRecord();
1589
1590  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
1591      new DownloadsDownloadFunction(), base::StringPrintf(
1592          "[{\"url\": \"%s\","
1593          "  \"filename\": \"sub/dir/ect/ory.txt\"}]",
1594          download_url.c_str())));
1595  ASSERT_TRUE(result.get());
1596  int result_id = -1;
1597  ASSERT_TRUE(result->GetAsInteger(&result_id));
1598  DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
1599  ASSERT_TRUE(item);
1600  ScopedCancellingItem canceller(item);
1601  ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
1602
1603  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
1604      base::StringPrintf("[{\"danger\": \"safe\","
1605                         "  \"incognito\": false,"
1606                         "  \"mime\": \"text/plain\","
1607                         "  \"paused\": false,"
1608                         "  \"url\": \"%s\"}]",
1609                         download_url.c_str())));
1610  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
1611      base::StringPrintf("[{\"id\": %d,"
1612                         "  \"filename\": {"
1613                         "    \"previous\": \"\","
1614                         "    \"current\": \"%s\"}}]",
1615                         result_id,
1616                         GetFilename("sub/dir/ect/ory.txt").c_str())));
1617  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
1618      base::StringPrintf("[{\"id\": %d,"
1619                         "  \"state\": {"
1620                         "    \"previous\": \"in_progress\","
1621                         "    \"current\": \"complete\"}}]",
1622                         result_id)));
1623}
1624
1625// Test that invalid filenames are disallowed.
1626IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
1627                       DownloadExtensionTest_Download_InvalidFilename) {
1628  LoadExtension("downloads_split");
1629  ASSERT_TRUE(StartEmbeddedTestServer());
1630  ASSERT_TRUE(test_server()->Start());
1631  std::string download_url = test_server()->GetURL("slow?0").spec();
1632  GoOnTheRecord();
1633
1634  EXPECT_STREQ(errors::kInvalidFilename,
1635                RunFunctionAndReturnError(new DownloadsDownloadFunction(),
1636                                          base::StringPrintf(
1637      "[{\"url\": \"%s\","
1638      "  \"filename\": \"../../../../../etc/passwd\"}]",
1639      download_url.c_str())).c_str());
1640}
1641
1642// Test that downloading invalid URLs immediately returns kInvalidURLError.
1643IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
1644                       DownloadExtensionTest_Download_InvalidURLs) {
1645  LoadExtension("downloads_split");
1646  GoOnTheRecord();
1647
1648  static const char* kInvalidURLs[] = {
1649    "foo bar",
1650    "../hello",
1651    "/hello",
1652    "http://",
1653    "#frag",
1654    "foo/bar.html#frag",
1655    "google.com/",
1656  };
1657
1658  for (size_t index = 0; index < arraysize(kInvalidURLs); ++index) {
1659    EXPECT_STREQ(errors::kInvalidURL,
1660                  RunFunctionAndReturnError(new DownloadsDownloadFunction(),
1661                                            base::StringPrintf(
1662        "[{\"url\": \"%s\"}]", kInvalidURLs[index])).c_str())
1663      << kInvalidURLs[index];
1664  }
1665
1666  EXPECT_STREQ("net::ERR_ACCESS_DENIED", RunFunctionAndReturnError(
1667      new DownloadsDownloadFunction(),
1668      "[{\"url\": \"javascript:document.write(\\\"hello\\\");\"}]").c_str());
1669  EXPECT_STREQ("net::ERR_ACCESS_DENIED", RunFunctionAndReturnError(
1670      new DownloadsDownloadFunction(),
1671      "[{\"url\": \"javascript:return false;\"}]").c_str());
1672  EXPECT_STREQ("net::ERR_NOT_IMPLEMENTED", RunFunctionAndReturnError(
1673      new DownloadsDownloadFunction(),
1674      "[{\"url\": \"ftp://example.com/example.txt\"}]").c_str());
1675}
1676
1677// TODO(benjhayden): Set up a test ftp server, add ftp://localhost* to
1678// permissions, test downloading from ftp.
1679
1680// Valid URLs plus fragments are still valid URLs.
1681IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
1682                       DownloadExtensionTest_Download_URLFragment) {
1683  LoadExtension("downloads_split");
1684  ASSERT_TRUE(StartEmbeddedTestServer());
1685  ASSERT_TRUE(test_server()->Start());
1686  std::string download_url = test_server()->GetURL("slow?0#fragment").spec();
1687  GoOnTheRecord();
1688
1689  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
1690      new DownloadsDownloadFunction(), base::StringPrintf(
1691          "[{\"url\": \"%s\"}]", download_url.c_str())));
1692  ASSERT_TRUE(result.get());
1693  int result_id = -1;
1694  ASSERT_TRUE(result->GetAsInteger(&result_id));
1695  DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
1696  ASSERT_TRUE(item);
1697  ScopedCancellingItem canceller(item);
1698  ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
1699
1700  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
1701      base::StringPrintf("[{\"danger\": \"safe\","
1702                         "  \"incognito\": false,"
1703                         "  \"mime\": \"text/plain\","
1704                         "  \"paused\": false,"
1705                         "  \"url\": \"%s\"}]",
1706                         download_url.c_str())));
1707  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
1708      base::StringPrintf("[{\"id\": %d,"
1709                         "  \"filename\": {"
1710                         "    \"previous\": \"\","
1711                         "    \"current\": \"%s\"}}]",
1712                         result_id,
1713                         GetFilename("slow.txt").c_str())));
1714  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
1715      base::StringPrintf("[{\"id\": %d,"
1716                         "  \"state\": {"
1717                         "    \"previous\": \"in_progress\","
1718                         "    \"current\": \"complete\"}}]",
1719                         result_id)));
1720}
1721
1722// Valid data URLs are valid URLs.
1723IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
1724                       DownloadExtensionTest_Download_DataURL) {
1725  LoadExtension("downloads_split");
1726  std::string download_url = "data:text/plain,hello";
1727  GoOnTheRecord();
1728
1729  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
1730        new DownloadsDownloadFunction(), base::StringPrintf(
1731      "[{\"url\": \"%s\","
1732      "  \"filename\": \"data.txt\"}]", download_url.c_str())));
1733  ASSERT_TRUE(result.get());
1734  int result_id = -1;
1735  ASSERT_TRUE(result->GetAsInteger(&result_id));
1736  DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
1737  ASSERT_TRUE(item);
1738  ScopedCancellingItem canceller(item);
1739  ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
1740
1741  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
1742      base::StringPrintf("[{\"danger\": \"safe\","
1743                         "  \"incognito\": false,"
1744                         "  \"mime\": \"text/plain\","
1745                         "  \"paused\": false,"
1746                         "  \"url\": \"%s\"}]",
1747                         download_url.c_str())));
1748  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
1749      base::StringPrintf("[{\"id\": %d,"
1750                         "  \"filename\": {"
1751                         "    \"previous\": \"\","
1752                         "    \"current\": \"%s\"}}]",
1753                         result_id,
1754                         GetFilename("data.txt").c_str())));
1755  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
1756      base::StringPrintf("[{\"id\": %d,"
1757                         "  \"state\": {"
1758                         "    \"previous\": \"in_progress\","
1759                         "    \"current\": \"complete\"}}]",
1760                         result_id)));
1761}
1762
1763// Valid file URLs are valid URLs.
1764#if defined(OS_WIN) && defined(USE_AURA)
1765// Disabled due to crbug.com/175711
1766#define MAYBE_DownloadExtensionTest_Download_File \
1767        DISABLED_DownloadExtensionTest_Download_File
1768#else
1769#define MAYBE_DownloadExtensionTest_Download_File \
1770        DownloadExtensionTest_Download_File
1771#endif
1772IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
1773                       MAYBE_DownloadExtensionTest_Download_File) {
1774  GoOnTheRecord();
1775  LoadExtension("downloads_split");
1776  std::string download_url = "file:///";
1777#if defined(OS_WIN)
1778  download_url += "C:/";
1779#endif
1780
1781  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
1782        new DownloadsDownloadFunction(), base::StringPrintf(
1783      "[{\"url\": \"%s\","
1784      "  \"filename\": \"file.txt\"}]", download_url.c_str())));
1785  ASSERT_TRUE(result.get());
1786  int result_id = -1;
1787  ASSERT_TRUE(result->GetAsInteger(&result_id));
1788  DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
1789  ASSERT_TRUE(item);
1790  ScopedCancellingItem canceller(item);
1791  ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
1792
1793  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
1794      base::StringPrintf("[{\"danger\": \"safe\","
1795                          "  \"incognito\": false,"
1796                          "  \"mime\": \"text/html\","
1797                          "  \"paused\": false,"
1798                          "  \"url\": \"%s\"}]",
1799                          download_url.c_str())));
1800  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
1801      base::StringPrintf("[{\"id\": %d,"
1802                          "  \"filename\": {"
1803                          "    \"previous\": \"\","
1804                          "    \"current\": \"%s\"}}]",
1805                          result_id,
1806                          GetFilename("file.txt").c_str())));
1807  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
1808      base::StringPrintf("[{\"id\": %d,"
1809                          "  \"state\": {"
1810                          "    \"previous\": \"in_progress\","
1811                          "    \"current\": \"complete\"}}]",
1812                          result_id)));
1813}
1814
1815// Test that auth-basic-succeed would fail if the resource requires the
1816// Authorization header and chrome fails to propagate it back to the server.
1817// This tests both that testserver.py does not succeed when it should fail as
1818// well as how the downloads extension API exposes the failure to extensions.
1819IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
1820                       DownloadExtensionTest_Download_AuthBasic_Fail) {
1821  LoadExtension("downloads_split");
1822  ASSERT_TRUE(StartEmbeddedTestServer());
1823  ASSERT_TRUE(test_server()->Start());
1824  std::string download_url = test_server()->GetURL("auth-basic").spec();
1825  GoOnTheRecord();
1826
1827  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
1828        new DownloadsDownloadFunction(), base::StringPrintf(
1829      "[{\"url\": \"%s\","
1830      "  \"filename\": \"auth-basic-fail.txt\"}]",
1831      download_url.c_str())));
1832  ASSERT_TRUE(result.get());
1833  int result_id = -1;
1834  ASSERT_TRUE(result->GetAsInteger(&result_id));
1835  DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
1836  ASSERT_TRUE(item);
1837  ScopedCancellingItem canceller(item);
1838  ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
1839
1840  ASSERT_TRUE(WaitForInterruption(
1841      item,
1842      content::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED,
1843      base::StringPrintf("[{\"danger\": \"safe\","
1844                         "  \"incognito\": false,"
1845                         "  \"mime\": \"text/html\","
1846                         "  \"paused\": false,"
1847                         "  \"url\": \"%s\"}]",
1848                         download_url.c_str())));
1849}
1850
1851// Test that DownloadsDownloadFunction propagates |headers| to the URLRequest.
1852IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
1853                       DownloadExtensionTest_Download_Headers) {
1854  LoadExtension("downloads_split");
1855  ASSERT_TRUE(StartEmbeddedTestServer());
1856  ASSERT_TRUE(test_server()->Start());
1857  std::string download_url = test_server()->GetURL("files/downloads/"
1858      "a_zip_file.zip?expected_headers=Foo:bar&expected_headers=Qx:yo").spec();
1859  GoOnTheRecord();
1860
1861  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
1862        new DownloadsDownloadFunction(), base::StringPrintf(
1863      "[{\"url\": \"%s\","
1864      "  \"filename\": \"headers-succeed.txt\","
1865      "  \"headers\": ["
1866      "    {\"name\": \"Foo\", \"value\": \"bar\"},"
1867      "    {\"name\": \"Qx\", \"value\":\"yo\"}]}]",
1868      download_url.c_str())));
1869  ASSERT_TRUE(result.get());
1870  int result_id = -1;
1871  ASSERT_TRUE(result->GetAsInteger(&result_id));
1872  DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
1873  ASSERT_TRUE(item);
1874  ScopedCancellingItem canceller(item);
1875  ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
1876
1877  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
1878      base::StringPrintf("[{\"danger\": \"safe\","
1879                         "  \"incognito\": false,"
1880                         "  \"mime\": \"application/octet-stream\","
1881                         "  \"paused\": false,"
1882                         "  \"url\": \"%s\"}]",
1883                         download_url.c_str())));
1884  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
1885      base::StringPrintf("[{\"id\": %d,"
1886                         "  \"filename\": {"
1887                         "    \"previous\": \"\","
1888                         "    \"current\": \"%s\"}}]",
1889                         result_id,
1890                         GetFilename("headers-succeed.txt").c_str())));
1891  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
1892      base::StringPrintf("[{\"id\": %d,"
1893                         "  \"state\": {"
1894                         "    \"previous\": \"in_progress\","
1895                         "    \"current\": \"complete\"}}]",
1896                         result_id)));
1897}
1898
1899// Test that headers-succeed would fail if the resource requires the headers and
1900// chrome fails to propagate them back to the server.  This tests both that
1901// testserver.py does not succeed when it should fail as well as how the
1902// downloads extension api exposes the failure to extensions.
1903IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
1904                       DownloadExtensionTest_Download_Headers_Fail) {
1905  LoadExtension("downloads_split");
1906  ASSERT_TRUE(StartEmbeddedTestServer());
1907  ASSERT_TRUE(test_server()->Start());
1908  std::string download_url = test_server()->GetURL("files/downloads/"
1909      "a_zip_file.zip?expected_headers=Foo:bar&expected_headers=Qx:yo").spec();
1910  GoOnTheRecord();
1911
1912  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
1913        new DownloadsDownloadFunction(), base::StringPrintf(
1914      "[{\"url\": \"%s\","
1915      "  \"filename\": \"headers-fail.txt\"}]",
1916      download_url.c_str())));
1917  ASSERT_TRUE(result.get());
1918  int result_id = -1;
1919  ASSERT_TRUE(result->GetAsInteger(&result_id));
1920  DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
1921  ASSERT_TRUE(item);
1922  ScopedCancellingItem canceller(item);
1923  ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
1924
1925  ASSERT_TRUE(WaitForInterruption(
1926      item,
1927      content::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT,
1928      base::StringPrintf("[{\"danger\": \"safe\","
1929                         "  \"incognito\": false,"
1930                         "  \"bytesReceived\": 0,"
1931                         "  \"mime\": \"\","
1932                         "  \"paused\": false,"
1933                         "  \"url\": \"%s\"}]",
1934                         download_url.c_str())));
1935}
1936
1937// Test that DownloadsDownloadFunction propagates the Authorization header
1938// correctly.
1939IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
1940                       DownloadExtensionTest_Download_AuthBasic) {
1941  LoadExtension("downloads_split");
1942  ASSERT_TRUE(StartEmbeddedTestServer());
1943  ASSERT_TRUE(test_server()->Start());
1944  std::string download_url = test_server()->GetURL("auth-basic").spec();
1945  // This is just base64 of 'username:secret'.
1946  static const char* kAuthorization = "dXNlcm5hbWU6c2VjcmV0";
1947  GoOnTheRecord();
1948
1949  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
1950        new DownloadsDownloadFunction(), base::StringPrintf(
1951      "[{\"url\": \"%s\","
1952      "  \"filename\": \"auth-basic-succeed.txt\","
1953      "  \"headers\": [{"
1954      "    \"name\": \"Authorization\","
1955      "    \"value\": \"Basic %s\"}]}]",
1956      download_url.c_str(), kAuthorization)));
1957  ASSERT_TRUE(result.get());
1958  int result_id = -1;
1959  ASSERT_TRUE(result->GetAsInteger(&result_id));
1960  DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
1961  ASSERT_TRUE(item);
1962  ScopedCancellingItem canceller(item);
1963  ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
1964
1965  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
1966      base::StringPrintf("[{\"danger\": \"safe\","
1967                          "  \"incognito\": false,"
1968                          "  \"mime\": \"text/html\","
1969                          "  \"paused\": false,"
1970                          "  \"url\": \"%s\"}]", download_url.c_str())));
1971  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
1972      base::StringPrintf("[{\"id\": %d,"
1973                          "  \"state\": {"
1974                          "    \"previous\": \"in_progress\","
1975                          "    \"current\": \"complete\"}}]", result_id)));
1976}
1977
1978// Test that DownloadsDownloadFunction propagates the |method| and |body|
1979// parameters to the URLRequest.
1980IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
1981                       DownloadExtensionTest_Download_Post) {
1982  LoadExtension("downloads_split");
1983  ASSERT_TRUE(StartEmbeddedTestServer());
1984  ASSERT_TRUE(test_server()->Start());
1985  std::string download_url = test_server()->GetURL("files/post/downloads/"
1986      "a_zip_file.zip?expected_body=BODY").spec();
1987  GoOnTheRecord();
1988
1989  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
1990        new DownloadsDownloadFunction(), base::StringPrintf(
1991      "[{\"url\": \"%s\","
1992      "  \"filename\": \"post-succeed.txt\","
1993      "  \"method\": \"POST\","
1994      "  \"body\": \"BODY\"}]",
1995      download_url.c_str())));
1996  ASSERT_TRUE(result.get());
1997  int result_id = -1;
1998  ASSERT_TRUE(result->GetAsInteger(&result_id));
1999  DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
2000  ASSERT_TRUE(item);
2001  ScopedCancellingItem canceller(item);
2002  ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
2003
2004  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
2005      base::StringPrintf("[{\"danger\": \"safe\","
2006                         "  \"incognito\": false,"
2007                         "  \"mime\": \"application/octet-stream\","
2008                         "  \"paused\": false,"
2009                         "  \"url\": \"%s\"}]", download_url.c_str())));
2010  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
2011      base::StringPrintf("[{\"id\": %d,"
2012                         "  \"filename\": {"
2013                         "    \"previous\": \"\","
2014                         "    \"current\": \"%s\"}}]",
2015                         result_id,
2016                         GetFilename("post-succeed.txt").c_str())));
2017  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
2018      base::StringPrintf("[{\"id\": %d,"
2019                         "  \"state\": {"
2020                         "    \"previous\": \"in_progress\","
2021                         "    \"current\": \"complete\"}}]",
2022                         result_id)));
2023}
2024
2025// Test that downloadPostSuccess would fail if the resource requires the POST
2026// method, and chrome fails to propagate the |method| parameter back to the
2027// server. This tests both that testserver.py does not succeed when it should
2028// fail, and this tests how the downloads extension api exposes the failure to
2029// extensions.
2030IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
2031                       DownloadExtensionTest_Download_Post_Get) {
2032  LoadExtension("downloads_split");
2033  ASSERT_TRUE(StartEmbeddedTestServer());
2034  ASSERT_TRUE(test_server()->Start());
2035  std::string download_url = test_server()->GetURL("files/post/downloads/"
2036      "a_zip_file.zip?expected_body=BODY").spec();
2037  GoOnTheRecord();
2038
2039  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
2040        new DownloadsDownloadFunction(), base::StringPrintf(
2041      "[{\"url\": \"%s\","
2042      "  \"body\": \"BODY\","
2043      "  \"filename\": \"post-get.txt\"}]",
2044      download_url.c_str())));
2045  ASSERT_TRUE(result.get());
2046  int result_id = -1;
2047  ASSERT_TRUE(result->GetAsInteger(&result_id));
2048  DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
2049  ASSERT_TRUE(item);
2050  ScopedCancellingItem canceller(item);
2051  ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
2052
2053  ASSERT_TRUE(WaitForInterruption(
2054      item,
2055      content::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT,
2056      base::StringPrintf("[{\"danger\": \"safe\","
2057                         "  \"incognito\": false,"
2058                         "  \"mime\": \"\","
2059                         "  \"paused\": false,"
2060                         "  \"id\": %d,"
2061                         "  \"url\": \"%s\"}]",
2062                         result_id,
2063                         download_url.c_str())));
2064}
2065
2066// Test that downloadPostSuccess would fail if the resource requires the POST
2067// method, and chrome fails to propagate the |body| parameter back to the
2068// server. This tests both that testserver.py does not succeed when it should
2069// fail, and this tests how the downloads extension api exposes the failure to
2070// extensions.
2071IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
2072                       DownloadExtensionTest_Download_Post_NoBody) {
2073  LoadExtension("downloads_split");
2074  ASSERT_TRUE(StartEmbeddedTestServer());
2075  ASSERT_TRUE(test_server()->Start());
2076  std::string download_url = test_server()->GetURL("files/post/downloads/"
2077      "a_zip_file.zip?expected_body=BODY").spec();
2078  GoOnTheRecord();
2079
2080  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
2081      new DownloadsDownloadFunction(), base::StringPrintf(
2082      "[{\"url\": \"%s\","
2083      "  \"method\": \"POST\","
2084      "  \"filename\": \"post-nobody.txt\"}]",
2085      download_url.c_str())));
2086  ASSERT_TRUE(result.get());
2087  int result_id = -1;
2088  ASSERT_TRUE(result->GetAsInteger(&result_id));
2089  DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
2090  ASSERT_TRUE(item);
2091  ScopedCancellingItem canceller(item);
2092  ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
2093
2094  ASSERT_TRUE(WaitForInterruption(
2095      item,
2096      content::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT,
2097      base::StringPrintf("[{\"danger\": \"safe\","
2098                         "  \"incognito\": false,"
2099                         "  \"mime\": \"\","
2100                         "  \"paused\": false,"
2101                         "  \"id\": %d,"
2102                         "  \"url\": \"%s\"}]",
2103                         result_id,
2104                         download_url.c_str())));
2105}
2106
2107// Test that cancel()ing an in-progress download causes its state to transition
2108// to interrupted, and test that that state transition is detectable by an
2109// onChanged event listener.  TODO(benjhayden): Test other sources of
2110// interruptions such as server death.
2111IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
2112                       DownloadExtensionTest_Download_Cancel) {
2113  LoadExtension("downloads_split");
2114  ASSERT_TRUE(StartEmbeddedTestServer());
2115  ASSERT_TRUE(test_server()->Start());
2116  std::string download_url = test_server()->GetURL(
2117      "download-known-size").spec();
2118  GoOnTheRecord();
2119
2120  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
2121      new DownloadsDownloadFunction(), base::StringPrintf(
2122          "[{\"url\": \"%s\"}]", download_url.c_str())));
2123  ASSERT_TRUE(result.get());
2124  int result_id = -1;
2125  ASSERT_TRUE(result->GetAsInteger(&result_id));
2126  DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
2127  ASSERT_TRUE(item);
2128  ScopedCancellingItem canceller(item);
2129  ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
2130
2131  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
2132      base::StringPrintf("[{\"danger\": \"safe\","
2133                          "  \"incognito\": false,"
2134                          "  \"mime\": \"application/octet-stream\","
2135                          "  \"paused\": false,"
2136                          "  \"id\": %d,"
2137                          "  \"url\": \"%s\"}]",
2138                          result_id,
2139                          download_url.c_str())));
2140  item->Cancel(true);
2141  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
2142      base::StringPrintf("[{\"id\": %d,"
2143                          "  \"error\": {\"current\":\"USER_CANCELED\"},"
2144                          "  \"state\": {"
2145                          "    \"previous\": \"in_progress\","
2146                          "    \"current\": \"interrupted\"}}]",
2147                          result_id)));
2148}
2149
2150// Test downloading filesystem: URLs.
2151// NOTE: chrome disallows creating HTML5 FileSystem Files in incognito.
2152IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
2153                       DownloadExtensionTest_Download_FileSystemURL) {
2154  static const char* kPayloadData = "on the record\ndata";
2155  GoOnTheRecord();
2156  LoadExtension("downloads_split");
2157
2158  const std::string download_url = "filesystem:" + GetExtensionURL() +
2159    "temporary/on_record.txt";
2160
2161  // Setup a file in the filesystem which we can download.
2162  ASSERT_TRUE(HTML5FileWriter::CreateFileForTesting(
2163      BrowserContext::GetDefaultStoragePartition(browser()->profile())->
2164          GetFileSystemContext(),
2165      fileapi::FileSystemURL::CreateForTest(GURL(download_url)),
2166      kPayloadData, strlen(kPayloadData)));
2167
2168  // Now download it.
2169  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
2170      new DownloadsDownloadFunction(), base::StringPrintf(
2171          "[{\"url\": \"%s\"}]", download_url.c_str())));
2172  ASSERT_TRUE(result.get());
2173  int result_id = -1;
2174  ASSERT_TRUE(result->GetAsInteger(&result_id));
2175
2176  DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
2177  ASSERT_TRUE(item);
2178  ScopedCancellingItem canceller(item);
2179  ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
2180
2181  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
2182      base::StringPrintf("[{\"danger\": \"safe\","
2183                          "  \"incognito\": false,"
2184                          "  \"mime\": \"text/plain\","
2185                          "  \"paused\": false,"
2186                          "  \"url\": \"%s\"}]",
2187                          download_url.c_str())));
2188  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
2189      base::StringPrintf("[{\"id\": %d,"
2190                          "  \"filename\": {"
2191                          "    \"previous\": \"\","
2192                          "    \"current\": \"%s\"}}]",
2193                          result_id,
2194                          GetFilename("on_record.txt").c_str())));
2195  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
2196      base::StringPrintf("[{\"id\": %d,"
2197                          "  \"state\": {"
2198                          "    \"previous\": \"in_progress\","
2199                          "    \"current\": \"complete\"}}]",
2200                          result_id)));
2201  std::string disk_data;
2202  EXPECT_TRUE(file_util::ReadFileToString(item->GetTargetFilePath(),
2203                                          &disk_data));
2204  EXPECT_STREQ(kPayloadData, disk_data.c_str());
2205}
2206
2207IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
2208                       DownloadExtensionTest_OnDeterminingFilename_NoChange) {
2209  GoOnTheRecord();
2210  LoadExtension("downloads_split");
2211  AddFilenameDeterminer();
2212  ASSERT_TRUE(StartEmbeddedTestServer());
2213  ASSERT_TRUE(test_server()->Start());
2214  std::string download_url = test_server()->GetURL("slow?0").spec();
2215
2216  // Start downloading a file.
2217  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
2218      new DownloadsDownloadFunction(), base::StringPrintf(
2219          "[{\"url\": \"%s\"}]", download_url.c_str())));
2220  ASSERT_TRUE(result.get());
2221  int result_id = -1;
2222  ASSERT_TRUE(result->GetAsInteger(&result_id));
2223  DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
2224  ASSERT_TRUE(item);
2225  ScopedCancellingItem canceller(item);
2226  ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
2227
2228  // Wait for the onCreated and onDeterminingFilename events.
2229  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
2230      base::StringPrintf("[{\"danger\": \"safe\","
2231                          "  \"incognito\": false,"
2232                          "  \"id\": %d,"
2233                          "  \"mime\": \"text/plain\","
2234                          "  \"paused\": false,"
2235                          "  \"url\": \"%s\"}]",
2236                          result_id,
2237                          download_url.c_str())));
2238  ASSERT_TRUE(WaitFor(
2239      events::kOnDownloadDeterminingFilename,
2240      base::StringPrintf("[{\"id\": %d,"
2241                         "  \"filename\":\"slow.txt\"}]",
2242                         result_id)));
2243  ASSERT_TRUE(item->GetTargetFilePath().empty());
2244  ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
2245
2246  // Respond to the onDeterminingFilename.
2247  std::string error;
2248  ASSERT_TRUE(ExtensionDownloadsEventRouter::DetermineFilename(
2249      browser()->profile(),
2250      false,
2251      GetExtensionId(),
2252      result_id,
2253      base::FilePath(),
2254      api::FILENAME_CONFLICT_ACTION_UNIQUIFY,
2255      &error));
2256  EXPECT_EQ("", error);
2257
2258  // The download should complete successfully.
2259  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
2260      base::StringPrintf("[{\"id\": %d,"
2261                         "  \"filename\": {"
2262                         "    \"previous\": \"\","
2263                         "    \"current\": \"%s\"}}]",
2264                         result_id,
2265                         GetFilename("slow.txt").c_str())));
2266  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
2267      base::StringPrintf("[{\"id\": %d,"
2268                         "  \"state\": {"
2269                         "    \"previous\": \"in_progress\","
2270                         "    \"current\": \"complete\"}}]",
2271                         result_id)));
2272}
2273
2274IN_PROC_BROWSER_TEST_F(
2275    DownloadExtensionTest,
2276    DownloadExtensionTest_OnDeterminingFilename_DangerousOverride) {
2277  GoOnTheRecord();
2278  LoadExtension("downloads_split");
2279  AddFilenameDeterminer();
2280  ASSERT_TRUE(StartEmbeddedTestServer());
2281  ASSERT_TRUE(test_server()->Start());
2282  std::string download_url = test_server()->GetURL("slow?0").spec();
2283
2284  // Start downloading a file.
2285  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
2286      new DownloadsDownloadFunction(), base::StringPrintf(
2287          "[{\"url\": \"%s\"}]", download_url.c_str())));
2288  ASSERT_TRUE(result.get());
2289  int result_id = -1;
2290  ASSERT_TRUE(result->GetAsInteger(&result_id));
2291  DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
2292  ASSERT_TRUE(item);
2293  ScopedCancellingItem canceller(item);
2294  ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
2295
2296  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
2297      base::StringPrintf("[{\"danger\": \"safe\","
2298                          "  \"incognito\": false,"
2299                          "  \"id\": %d,"
2300                          "  \"mime\": \"text/plain\","
2301                          "  \"paused\": false,"
2302                          "  \"url\": \"%s\"}]",
2303                          result_id,
2304                          download_url.c_str())));
2305  ASSERT_TRUE(WaitFor(
2306      events::kOnDownloadDeterminingFilename,
2307      base::StringPrintf("[{\"id\": %d,"
2308                         "  \"filename\":\"slow.txt\"}]",
2309                         result_id)));
2310  ASSERT_TRUE(item->GetTargetFilePath().empty());
2311  ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
2312
2313  // Respond to the onDeterminingFilename.
2314  std::string error;
2315  ASSERT_TRUE(ExtensionDownloadsEventRouter::DetermineFilename(
2316      browser()->profile(),
2317      false,
2318      GetExtensionId(),
2319      result_id,
2320      base::FilePath(FILE_PATH_LITERAL("overridden.swf")),
2321      api::FILENAME_CONFLICT_ACTION_UNIQUIFY,
2322      &error));
2323  EXPECT_EQ("", error);
2324
2325  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
2326      base::StringPrintf("[{\"id\": %d,"
2327                         "  \"danger\": {"
2328                         "    \"previous\":\"safe\","
2329                         "    \"current\":\"file\"}}]",
2330                         result_id)));
2331
2332  item->ValidateDangerousDownload();
2333  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
2334      base::StringPrintf("[{\"id\": %d,"
2335                         "  \"danger\": {"
2336                         "    \"previous\":\"file\","
2337                         "    \"current\":\"accepted\"}}]",
2338                         result_id)));
2339  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
2340      base::StringPrintf("[{\"id\": %d,"
2341                          "  \"state\": {"
2342                          "    \"previous\": \"in_progress\","
2343                          "    \"current\": \"complete\"}}]",
2344                          result_id)));
2345  EXPECT_EQ(downloads_directory().AppendASCII("overridden.swf"),
2346            item->GetTargetFilePath());
2347}
2348
2349IN_PROC_BROWSER_TEST_F(
2350    DownloadExtensionTest,
2351    DownloadExtensionTest_OnDeterminingFilename_ReferencesParentInvalid) {
2352  GoOnTheRecord();
2353  LoadExtension("downloads_split");
2354  AddFilenameDeterminer();
2355  ASSERT_TRUE(StartEmbeddedTestServer());
2356  ASSERT_TRUE(test_server()->Start());
2357  std::string download_url = test_server()->GetURL("slow?0").spec();
2358
2359  // Start downloading a file.
2360  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
2361      new DownloadsDownloadFunction(), base::StringPrintf(
2362          "[{\"url\": \"%s\"}]", download_url.c_str())));
2363  ASSERT_TRUE(result.get());
2364  int result_id = -1;
2365  ASSERT_TRUE(result->GetAsInteger(&result_id));
2366  DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
2367  ASSERT_TRUE(item);
2368  ScopedCancellingItem canceller(item);
2369  ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
2370
2371  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
2372      base::StringPrintf("[{\"danger\": \"safe\","
2373                          "  \"incognito\": false,"
2374                          "  \"id\": %d,"
2375                          "  \"mime\": \"text/plain\","
2376                          "  \"paused\": false,"
2377                          "  \"url\": \"%s\"}]",
2378                          result_id,
2379                          download_url.c_str())));
2380  ASSERT_TRUE(WaitFor(
2381      events::kOnDownloadDeterminingFilename,
2382      base::StringPrintf("[{\"id\": %d,"
2383                         "  \"filename\":\"slow.txt\"}]",
2384                         result_id)));
2385  ASSERT_TRUE(item->GetTargetFilePath().empty());
2386  ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
2387
2388  // Respond to the onDeterminingFilename.
2389  std::string error;
2390  ASSERT_FALSE(ExtensionDownloadsEventRouter::DetermineFilename(
2391      browser()->profile(),
2392      false,
2393      GetExtensionId(),
2394      result_id,
2395      base::FilePath(FILE_PATH_LITERAL("sneaky/../../sneaky.txt")),
2396      api::FILENAME_CONFLICT_ACTION_UNIQUIFY,
2397      &error));
2398  EXPECT_STREQ(errors::kInvalidFilename, error.c_str());
2399  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
2400      base::StringPrintf("[{\"id\": %d,"
2401                          "  \"filename\": {"
2402                          "    \"previous\": \"\","
2403                          "    \"current\": \"%s\"}}]",
2404                          result_id,
2405                          GetFilename("slow.txt").c_str())));
2406  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
2407      base::StringPrintf("[{\"id\": %d,"
2408                          "  \"state\": {"
2409                          "    \"previous\": \"in_progress\","
2410                          "    \"current\": \"complete\"}}]",
2411                          result_id)));
2412}
2413
2414IN_PROC_BROWSER_TEST_F(
2415    DownloadExtensionTest,
2416    DownloadExtensionTest_OnDeterminingFilename_IllegalFilename) {
2417  GoOnTheRecord();
2418  LoadExtension("downloads_split");
2419  AddFilenameDeterminer();
2420  ASSERT_TRUE(StartEmbeddedTestServer());
2421  ASSERT_TRUE(test_server()->Start());
2422  std::string download_url = test_server()->GetURL("slow?0").spec();
2423
2424  // Start downloading a file.
2425  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
2426      new DownloadsDownloadFunction(), base::StringPrintf(
2427          "[{\"url\": \"%s\"}]", download_url.c_str())));
2428  ASSERT_TRUE(result.get());
2429  int result_id = -1;
2430  ASSERT_TRUE(result->GetAsInteger(&result_id));
2431  DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
2432  ASSERT_TRUE(item);
2433  ScopedCancellingItem canceller(item);
2434  ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
2435
2436  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
2437      base::StringPrintf("[{\"danger\": \"safe\","
2438                          "  \"incognito\": false,"
2439                          "  \"id\": %d,"
2440                          "  \"mime\": \"text/plain\","
2441                          "  \"paused\": false,"
2442                          "  \"url\": \"%s\"}]",
2443                          result_id,
2444                          download_url.c_str())));
2445  ASSERT_TRUE(WaitFor(
2446      events::kOnDownloadDeterminingFilename,
2447      base::StringPrintf("[{\"id\": %d,"
2448                         "  \"filename\":\"slow.txt\"}]",
2449                         result_id)));
2450  ASSERT_TRUE(item->GetTargetFilePath().empty());
2451  ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
2452
2453  // Respond to the onDeterminingFilename.
2454  std::string error;
2455  ASSERT_FALSE(ExtensionDownloadsEventRouter::DetermineFilename(
2456      browser()->profile(),
2457      false,
2458      GetExtensionId(),
2459      result_id,
2460      base::FilePath(FILE_PATH_LITERAL("<")),
2461      api::FILENAME_CONFLICT_ACTION_UNIQUIFY,
2462      &error));
2463  EXPECT_STREQ(errors::kInvalidFilename, error.c_str());
2464  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged, base::StringPrintf(
2465      "[{\"id\": %d,"
2466      "  \"filename\": {"
2467      "    \"previous\": \"\","
2468      "    \"current\": \"%s\"}}]",
2469      result_id,
2470      GetFilename("slow.txt").c_str())));
2471  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged, base::StringPrintf(
2472      "[{\"id\": %d,"
2473      "  \"state\": {"
2474      "    \"previous\": \"in_progress\","
2475      "    \"current\": \"complete\"}}]",
2476      result_id)));
2477}
2478
2479IN_PROC_BROWSER_TEST_F(
2480    DownloadExtensionTest,
2481    DownloadExtensionTest_OnDeterminingFilename_IllegalFilenameExtension) {
2482  GoOnTheRecord();
2483  LoadExtension("downloads_split");
2484  AddFilenameDeterminer();
2485  ASSERT_TRUE(StartEmbeddedTestServer());
2486  ASSERT_TRUE(test_server()->Start());
2487  std::string download_url = test_server()->GetURL("slow?0").spec();
2488
2489  // Start downloading a file.
2490  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
2491      new DownloadsDownloadFunction(), base::StringPrintf(
2492          "[{\"url\": \"%s\"}]", download_url.c_str())));
2493  ASSERT_TRUE(result.get());
2494  int result_id = -1;
2495  ASSERT_TRUE(result->GetAsInteger(&result_id));
2496  DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
2497  ASSERT_TRUE(item);
2498  ScopedCancellingItem canceller(item);
2499  ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
2500
2501  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
2502      base::StringPrintf("[{\"danger\": \"safe\","
2503                          "  \"incognito\": false,"
2504                          "  \"id\": %d,"
2505                          "  \"mime\": \"text/plain\","
2506                          "  \"paused\": false,"
2507                          "  \"url\": \"%s\"}]",
2508                          result_id,
2509                          download_url.c_str())));
2510  ASSERT_TRUE(WaitFor(
2511      events::kOnDownloadDeterminingFilename,
2512      base::StringPrintf("[{\"id\": %d,"
2513                         "  \"filename\":\"slow.txt\"}]",
2514                         result_id)));
2515  ASSERT_TRUE(item->GetTargetFilePath().empty());
2516  ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
2517
2518  // Respond to the onDeterminingFilename.
2519  std::string error;
2520  ASSERT_FALSE(ExtensionDownloadsEventRouter::DetermineFilename(
2521      browser()->profile(),
2522      false,
2523      GetExtensionId(),
2524      result_id,
2525      base::FilePath(FILE_PATH_LITERAL(
2526          "My Computer.{20D04FE0-3AEA-1069-A2D8-08002B30309D}/foo")),
2527      api::FILENAME_CONFLICT_ACTION_UNIQUIFY,
2528      &error));
2529  EXPECT_STREQ(errors::kInvalidFilename, error.c_str());
2530  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged, base::StringPrintf(
2531      "[{\"id\": %d,"
2532      "  \"filename\": {"
2533      "    \"previous\": \"\","
2534      "    \"current\": \"%s\"}}]",
2535      result_id,
2536      GetFilename("slow.txt").c_str())));
2537  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged, base::StringPrintf(
2538      "[{\"id\": %d,"
2539      "  \"state\": {"
2540      "    \"previous\": \"in_progress\","
2541      "    \"current\": \"complete\"}}]",
2542      result_id)));
2543}
2544
2545IN_PROC_BROWSER_TEST_F(
2546    DownloadExtensionTest,
2547    DownloadExtensionTest_OnDeterminingFilename_ReservedFilename) {
2548  GoOnTheRecord();
2549  LoadExtension("downloads_split");
2550  AddFilenameDeterminer();
2551  ASSERT_TRUE(StartEmbeddedTestServer());
2552  ASSERT_TRUE(test_server()->Start());
2553  std::string download_url = test_server()->GetURL("slow?0").spec();
2554
2555  // Start downloading a file.
2556  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
2557      new DownloadsDownloadFunction(), base::StringPrintf(
2558          "[{\"url\": \"%s\"}]", download_url.c_str())));
2559  ASSERT_TRUE(result.get());
2560  int result_id = -1;
2561  ASSERT_TRUE(result->GetAsInteger(&result_id));
2562  DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
2563  ASSERT_TRUE(item);
2564  ScopedCancellingItem canceller(item);
2565  ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
2566
2567  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
2568      base::StringPrintf("[{\"danger\": \"safe\","
2569                          "  \"incognito\": false,"
2570                          "  \"id\": %d,"
2571                          "  \"mime\": \"text/plain\","
2572                          "  \"paused\": false,"
2573                          "  \"url\": \"%s\"}]",
2574                          result_id,
2575                          download_url.c_str())));
2576  ASSERT_TRUE(WaitFor(
2577      events::kOnDownloadDeterminingFilename,
2578      base::StringPrintf("[{\"id\": %d,"
2579                         "  \"filename\":\"slow.txt\"}]",
2580                         result_id)));
2581  ASSERT_TRUE(item->GetTargetFilePath().empty());
2582  ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
2583
2584  // Respond to the onDeterminingFilename.
2585  std::string error;
2586  ASSERT_FALSE(ExtensionDownloadsEventRouter::DetermineFilename(
2587      browser()->profile(),
2588      false,
2589      GetExtensionId(),
2590      result_id,
2591      base::FilePath(FILE_PATH_LITERAL("con.foo")),
2592      api::FILENAME_CONFLICT_ACTION_UNIQUIFY,
2593      &error));
2594  EXPECT_STREQ(errors::kInvalidFilename, error.c_str());
2595  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged, base::StringPrintf(
2596      "[{\"id\": %d,"
2597      "  \"filename\": {"
2598      "    \"previous\": \"\","
2599      "    \"current\": \"%s\"}}]",
2600      result_id,
2601      GetFilename("slow.txt").c_str())));
2602  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged, base::StringPrintf(
2603      "[{\"id\": %d,"
2604      "  \"state\": {"
2605      "    \"previous\": \"in_progress\","
2606      "    \"current\": \"complete\"}}]",
2607      result_id)));
2608}
2609
2610IN_PROC_BROWSER_TEST_F(
2611    DownloadExtensionTest,
2612    DownloadExtensionTest_OnDeterminingFilename_CurDirInvalid) {
2613  GoOnTheRecord();
2614  LoadExtension("downloads_split");
2615  AddFilenameDeterminer();
2616  ASSERT_TRUE(StartEmbeddedTestServer());
2617  ASSERT_TRUE(test_server()->Start());
2618  std::string download_url = test_server()->GetURL("slow?0").spec();
2619
2620  // Start downloading a file.
2621  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
2622      new DownloadsDownloadFunction(), base::StringPrintf(
2623          "[{\"url\": \"%s\"}]", download_url.c_str())));
2624  ASSERT_TRUE(result.get());
2625  int result_id = -1;
2626  ASSERT_TRUE(result->GetAsInteger(&result_id));
2627  DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
2628  ASSERT_TRUE(item);
2629  ScopedCancellingItem canceller(item);
2630  ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
2631
2632  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
2633      base::StringPrintf("[{\"danger\": \"safe\","
2634                          "  \"incognito\": false,"
2635                          "  \"id\": %d,"
2636                          "  \"mime\": \"text/plain\","
2637                          "  \"paused\": false,"
2638                          "  \"url\": \"%s\"}]",
2639                          result_id,
2640                          download_url.c_str())));
2641  ASSERT_TRUE(WaitFor(
2642      events::kOnDownloadDeterminingFilename,
2643      base::StringPrintf("[{\"id\": %d,"
2644                         "  \"filename\":\"slow.txt\"}]",
2645                         result_id)));
2646  ASSERT_TRUE(item->GetTargetFilePath().empty());
2647  ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
2648
2649  // Respond to the onDeterminingFilename.
2650  std::string error;
2651  ASSERT_FALSE(ExtensionDownloadsEventRouter::DetermineFilename(
2652      browser()->profile(),
2653      false,
2654      GetExtensionId(),
2655      result_id,
2656      base::FilePath(FILE_PATH_LITERAL(".")),
2657      api::FILENAME_CONFLICT_ACTION_UNIQUIFY,
2658      &error));
2659  EXPECT_STREQ(errors::kInvalidFilename, error.c_str());
2660  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
2661      base::StringPrintf("[{\"id\": %d,"
2662                         "  \"filename\": {"
2663                         "    \"previous\": \"\","
2664                         "    \"current\": \"%s\"}}]",
2665                         result_id,
2666                         GetFilename("slow.txt").c_str())));
2667  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
2668      base::StringPrintf("[{\"id\": %d,"
2669                         "  \"state\": {"
2670                         "    \"previous\": \"in_progress\","
2671                         "    \"current\": \"complete\"}}]",
2672                         result_id)));
2673}
2674
2675IN_PROC_BROWSER_TEST_F(
2676    DownloadExtensionTest,
2677    DownloadExtensionTest_OnDeterminingFilename_ParentDirInvalid) {
2678  ASSERT_TRUE(StartEmbeddedTestServer());
2679  ASSERT_TRUE(test_server()->Start());
2680  GoOnTheRecord();
2681  LoadExtension("downloads_split");
2682  AddFilenameDeterminer();
2683  std::string download_url = test_server()->GetURL("slow?0").spec();
2684
2685  // Start downloading a file.
2686  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
2687      new DownloadsDownloadFunction(), base::StringPrintf(
2688          "[{\"url\": \"%s\"}]", download_url.c_str())));
2689  ASSERT_TRUE(result.get());
2690  int result_id = -1;
2691  ASSERT_TRUE(result->GetAsInteger(&result_id));
2692  DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
2693  ASSERT_TRUE(item);
2694  ScopedCancellingItem canceller(item);
2695  ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
2696
2697  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
2698      base::StringPrintf("[{\"danger\": \"safe\","
2699                          "  \"incognito\": false,"
2700                          "  \"id\": %d,"
2701                          "  \"mime\": \"text/plain\","
2702                          "  \"paused\": false,"
2703                          "  \"url\": \"%s\"}]",
2704                          result_id,
2705                          download_url.c_str())));
2706  ASSERT_TRUE(WaitFor(
2707      events::kOnDownloadDeterminingFilename,
2708      base::StringPrintf("[{\"id\": %d,"
2709                         "  \"filename\":\"slow.txt\"}]",
2710                         result_id)));
2711  ASSERT_TRUE(item->GetTargetFilePath().empty());
2712  ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
2713
2714  // Respond to the onDeterminingFilename.
2715  std::string error;
2716  ASSERT_FALSE(ExtensionDownloadsEventRouter::DetermineFilename(
2717      browser()->profile(),
2718      false,
2719      GetExtensionId(),
2720      result_id,
2721      base::FilePath(FILE_PATH_LITERAL("..")),
2722      api::FILENAME_CONFLICT_ACTION_UNIQUIFY,
2723      &error));
2724  EXPECT_STREQ(errors::kInvalidFilename, error.c_str());
2725  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
2726      base::StringPrintf("[{\"id\": %d,"
2727                         "  \"filename\": {"
2728                         "    \"previous\": \"\","
2729                         "    \"current\": \"%s\"}}]",
2730                         result_id,
2731                         GetFilename("slow.txt").c_str())));
2732  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
2733      base::StringPrintf("[{\"id\": %d,"
2734                         "  \"state\": {"
2735                         "    \"previous\": \"in_progress\","
2736                         "    \"current\": \"complete\"}}]",
2737                         result_id)));
2738}
2739
2740IN_PROC_BROWSER_TEST_F(
2741    DownloadExtensionTest,
2742    DownloadExtensionTest_OnDeterminingFilename_AbsPathInvalid) {
2743  GoOnTheRecord();
2744  LoadExtension("downloads_split");
2745  AddFilenameDeterminer();
2746  ASSERT_TRUE(StartEmbeddedTestServer());
2747  ASSERT_TRUE(test_server()->Start());
2748  std::string download_url = test_server()->GetURL("slow?0").spec();
2749
2750  // Start downloading a file.
2751  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
2752      new DownloadsDownloadFunction(), base::StringPrintf(
2753          "[{\"url\": \"%s\"}]", download_url.c_str())));
2754  ASSERT_TRUE(result.get());
2755  int result_id = -1;
2756  ASSERT_TRUE(result->GetAsInteger(&result_id));
2757  DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
2758  ASSERT_TRUE(item);
2759  ScopedCancellingItem canceller(item);
2760  ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
2761
2762  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
2763      base::StringPrintf("[{\"danger\": \"safe\","
2764                          "  \"incognito\": false,"
2765                          "  \"id\": %d,"
2766                          "  \"mime\": \"text/plain\","
2767                          "  \"paused\": false,"
2768                          "  \"url\": \"%s\"}]",
2769                          result_id,
2770                          download_url.c_str())));
2771  ASSERT_TRUE(WaitFor(
2772      events::kOnDownloadDeterminingFilename,
2773      base::StringPrintf("[{\"id\": %d,"
2774                         "  \"filename\":\"slow.txt\"}]",
2775                         result_id)));
2776  ASSERT_TRUE(item->GetTargetFilePath().empty());
2777  ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
2778
2779  // Respond to the onDeterminingFilename. Absolute paths should be rejected.
2780  std::string error;
2781  ASSERT_FALSE(ExtensionDownloadsEventRouter::DetermineFilename(
2782      browser()->profile(),
2783      false,
2784      GetExtensionId(),
2785      result_id,
2786      downloads_directory().Append(FILE_PATH_LITERAL("sneaky.txt")),
2787      api::FILENAME_CONFLICT_ACTION_UNIQUIFY,
2788      &error));
2789  EXPECT_STREQ(errors::kInvalidFilename, error.c_str());
2790
2791  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
2792      base::StringPrintf("[{\"id\": %d,"
2793                          "  \"filename\": {"
2794                          "    \"previous\": \"\","
2795                          "    \"current\": \"%s\"}}]",
2796                          result_id,
2797                          GetFilename("slow.txt").c_str())));
2798  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
2799      base::StringPrintf("[{\"id\": %d,"
2800                          "  \"state\": {"
2801                          "    \"previous\": \"in_progress\","
2802                          "    \"current\": \"complete\"}}]",
2803                          result_id)));
2804}
2805
2806IN_PROC_BROWSER_TEST_F(
2807    DownloadExtensionTest,
2808    DownloadExtensionTest_OnDeterminingFilename_EmptyBasenameInvalid) {
2809  GoOnTheRecord();
2810  LoadExtension("downloads_split");
2811  AddFilenameDeterminer();
2812  ASSERT_TRUE(StartEmbeddedTestServer());
2813  ASSERT_TRUE(test_server()->Start());
2814  std::string download_url = test_server()->GetURL("slow?0").spec();
2815
2816  // Start downloading a file.
2817  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
2818      new DownloadsDownloadFunction(), base::StringPrintf(
2819          "[{\"url\": \"%s\"}]", download_url.c_str())));
2820  ASSERT_TRUE(result.get());
2821  int result_id = -1;
2822  ASSERT_TRUE(result->GetAsInteger(&result_id));
2823  DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
2824  ASSERT_TRUE(item);
2825  ScopedCancellingItem canceller(item);
2826  ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
2827
2828  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
2829      base::StringPrintf("[{\"danger\": \"safe\","
2830                          "  \"incognito\": false,"
2831                          "  \"id\": %d,"
2832                          "  \"mime\": \"text/plain\","
2833                          "  \"paused\": false,"
2834                          "  \"url\": \"%s\"}]",
2835                          result_id,
2836                          download_url.c_str())));
2837  ASSERT_TRUE(WaitFor(
2838      events::kOnDownloadDeterminingFilename,
2839      base::StringPrintf("[{\"id\": %d,"
2840                         "  \"filename\":\"slow.txt\"}]",
2841                         result_id)));
2842  ASSERT_TRUE(item->GetTargetFilePath().empty());
2843  ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
2844
2845  // Respond to the onDeterminingFilename. Empty basenames should be rejected.
2846  std::string error;
2847  ASSERT_FALSE(ExtensionDownloadsEventRouter::DetermineFilename(
2848      browser()->profile(),
2849      false,
2850      GetExtensionId(),
2851      result_id,
2852      base::FilePath(FILE_PATH_LITERAL("foo/")),
2853      api::FILENAME_CONFLICT_ACTION_UNIQUIFY,
2854      &error));
2855  EXPECT_STREQ(errors::kInvalidFilename, error.c_str());
2856
2857  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
2858      base::StringPrintf("[{\"id\": %d,"
2859                         "  \"filename\": {"
2860                         "    \"previous\": \"\","
2861                         "    \"current\": \"%s\"}}]",
2862                         result_id,
2863                         GetFilename("slow.txt").c_str())));
2864  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
2865      base::StringPrintf("[{\"id\": %d,"
2866                         "  \"state\": {"
2867                         "    \"previous\": \"in_progress\","
2868                         "    \"current\": \"complete\"}}]",
2869                         result_id)));
2870}
2871
2872IN_PROC_BROWSER_TEST_F(
2873    DownloadExtensionTest,
2874    DownloadExtensionTest_OnDeterminingFilename_Override) {
2875  GoOnTheRecord();
2876  LoadExtension("downloads_split");
2877  AddFilenameDeterminer();
2878  ASSERT_TRUE(StartEmbeddedTestServer());
2879  ASSERT_TRUE(test_server()->Start());
2880  std::string download_url = test_server()->GetURL("slow?0").spec();
2881
2882  // Start downloading a file.
2883  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
2884      new DownloadsDownloadFunction(), base::StringPrintf(
2885          "[{\"url\": \"%s\"}]", download_url.c_str())));
2886  ASSERT_TRUE(result.get());
2887  int result_id = -1;
2888  ASSERT_TRUE(result->GetAsInteger(&result_id));
2889  DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
2890  ASSERT_TRUE(item);
2891  ScopedCancellingItem canceller(item);
2892  ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
2893  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
2894      base::StringPrintf("[{\"danger\": \"safe\","
2895                         "  \"incognito\": false,"
2896                         "  \"id\": %d,"
2897                         "  \"mime\": \"text/plain\","
2898                         "  \"paused\": false,"
2899                         "  \"url\": \"%s\"}]",
2900                         result_id,
2901                         download_url.c_str())));
2902  ASSERT_TRUE(WaitFor(
2903      events::kOnDownloadDeterminingFilename,
2904      base::StringPrintf("[{\"id\": %d,"
2905                         "  \"filename\":\"slow.txt\"}]",
2906                         result_id)));
2907  ASSERT_TRUE(item->GetTargetFilePath().empty());
2908  ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
2909
2910  // Respond to the onDeterminingFilename.
2911  std::string error;
2912  ASSERT_TRUE(ExtensionDownloadsEventRouter::DetermineFilename(
2913      browser()->profile(),
2914      false,
2915      GetExtensionId(),
2916      result_id,
2917      base::FilePath(),
2918      api::FILENAME_CONFLICT_ACTION_UNIQUIFY,
2919      &error));
2920  EXPECT_EQ("", error);
2921
2922  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
2923      base::StringPrintf("[{\"id\": %d,"
2924                         "  \"filename\": {"
2925                         "    \"previous\": \"\","
2926                         "    \"current\": \"%s\"}}]",
2927                         result_id,
2928                         GetFilename("slow.txt").c_str())));
2929  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
2930      base::StringPrintf("[{\"id\": %d,"
2931                         "  \"state\": {"
2932                         "    \"previous\": \"in_progress\","
2933                         "    \"current\": \"complete\"}}]",
2934                         result_id)));
2935
2936  // Start downloading a file.
2937  result.reset(RunFunctionAndReturnResult(
2938      new DownloadsDownloadFunction(), base::StringPrintf(
2939          "[{\"url\": \"%s\"}]", download_url.c_str())));
2940  ASSERT_TRUE(result.get());
2941  result_id = -1;
2942  ASSERT_TRUE(result->GetAsInteger(&result_id));
2943  item = GetCurrentManager()->GetDownload(result_id);
2944  ASSERT_TRUE(item);
2945  ScopedCancellingItem canceller2(item);
2946  ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
2947
2948  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
2949      base::StringPrintf("[{\"danger\": \"safe\","
2950                         "  \"incognito\": false,"
2951                         "  \"id\": %d,"
2952                         "  \"mime\": \"text/plain\","
2953                         "  \"paused\": false,"
2954                         "  \"url\": \"%s\"}]",
2955                         result_id,
2956                         download_url.c_str())));
2957  ASSERT_TRUE(WaitFor(
2958      events::kOnDownloadDeterminingFilename,
2959      base::StringPrintf("[{\"id\": %d,"
2960                         "  \"filename\":\"slow.txt\"}]",
2961                         result_id)));
2962  ASSERT_TRUE(item->GetTargetFilePath().empty());
2963  ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
2964
2965  // Respond to the onDeterminingFilename.
2966  // Also test that DetermineFilename allows (chrome) extensions to set
2967  // filenames without (filename) extensions. (Don't ask about v8 extensions or
2968  // python extensions or kernel extensions or firefox extensions...)
2969  error = "";
2970  ASSERT_TRUE(ExtensionDownloadsEventRouter::DetermineFilename(
2971      browser()->profile(),
2972      false,
2973      GetExtensionId(),
2974      result_id,
2975      base::FilePath(FILE_PATH_LITERAL("foo")),
2976      api::FILENAME_CONFLICT_ACTION_OVERWRITE,
2977      &error));
2978  EXPECT_EQ("", error);
2979
2980  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
2981      base::StringPrintf("[{\"id\": %d,"
2982                         "  \"filename\": {"
2983                         "    \"previous\": \"\","
2984                         "    \"current\": \"%s\"}}]",
2985                         result_id,
2986                         GetFilename("foo").c_str())));
2987  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
2988      base::StringPrintf("[{\"id\": %d,"
2989                         "  \"state\": {"
2990                         "    \"previous\": \"in_progress\","
2991                         "    \"current\": \"complete\"}}]",
2992                         result_id)));
2993}
2994
2995// TODO test precedence rules: install_time
2996
2997IN_PROC_BROWSER_TEST_F(
2998    DownloadExtensionTest,
2999    DownloadExtensionTest_OnDeterminingFilename_RemoveFilenameDeterminer) {
3000  ASSERT_TRUE(StartEmbeddedTestServer());
3001  ASSERT_TRUE(test_server()->Start());
3002  GoOnTheRecord();
3003  LoadExtension("downloads_split");
3004  content::RenderProcessHost* host = AddFilenameDeterminer();
3005  std::string download_url = test_server()->GetURL("slow?0").spec();
3006
3007  // Start downloading a file.
3008  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
3009      new DownloadsDownloadFunction(), base::StringPrintf(
3010          "[{\"url\": \"%s\"}]", download_url.c_str())));
3011  ASSERT_TRUE(result.get());
3012  int result_id = -1;
3013  ASSERT_TRUE(result->GetAsInteger(&result_id));
3014  DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
3015  ASSERT_TRUE(item);
3016  ScopedCancellingItem canceller(item);
3017  ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
3018
3019  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
3020      base::StringPrintf("[{\"danger\": \"safe\","
3021                          "  \"incognito\": false,"
3022                          "  \"id\": %d,"
3023                          "  \"mime\": \"text/plain\","
3024                          "  \"paused\": false,"
3025                          "  \"url\": \"%s\"}]",
3026                          result_id,
3027                          download_url.c_str())));
3028  ASSERT_TRUE(WaitFor(
3029      events::kOnDownloadDeterminingFilename,
3030      base::StringPrintf("[{\"id\": %d,"
3031                         "  \"filename\":\"slow.txt\"}]",
3032                         result_id)));
3033  ASSERT_TRUE(item->GetTargetFilePath().empty());
3034  ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
3035
3036  // Remove a determiner while waiting for it.
3037  RemoveFilenameDeterminer(host);
3038
3039  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
3040      base::StringPrintf("[{\"id\": %d,"
3041                         "  \"state\": {"
3042                         "    \"previous\": \"in_progress\","
3043                         "    \"current\": \"complete\"}}]",
3044                         result_id)));
3045}
3046
3047IN_PROC_BROWSER_TEST_F(
3048    DownloadExtensionTest,
3049    DownloadExtensionTest_OnDeterminingFilename_IncognitoSplit) {
3050  LoadExtension("downloads_split");
3051  ASSERT_TRUE(StartEmbeddedTestServer());
3052  ASSERT_TRUE(test_server()->Start());
3053  std::string download_url = test_server()->GetURL("slow?0").spec();
3054
3055  GoOnTheRecord();
3056  AddFilenameDeterminer();
3057
3058  GoOffTheRecord();
3059  AddFilenameDeterminer();
3060
3061  // Start an on-record download.
3062  GoOnTheRecord();
3063  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
3064      new DownloadsDownloadFunction(), base::StringPrintf(
3065          "[{\"url\": \"%s\"}]", download_url.c_str())));
3066  ASSERT_TRUE(result.get());
3067  int result_id = -1;
3068  ASSERT_TRUE(result->GetAsInteger(&result_id));
3069  DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
3070  ASSERT_TRUE(item);
3071  ScopedCancellingItem canceller(item);
3072  ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
3073
3074  // Wait for the onCreated and onDeterminingFilename events.
3075  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
3076      base::StringPrintf("[{\"danger\": \"safe\","
3077                          "  \"incognito\": false,"
3078                          "  \"id\": %d,"
3079                          "  \"mime\": \"text/plain\","
3080                          "  \"paused\": false,"
3081                          "  \"url\": \"%s\"}]",
3082                          result_id,
3083                          download_url.c_str())));
3084  ASSERT_TRUE(WaitFor(
3085      events::kOnDownloadDeterminingFilename,
3086      base::StringPrintf("[{\"id\": %d,"
3087                         "  \"incognito\": false,"
3088                         "  \"filename\":\"slow.txt\"}]",
3089                         result_id)));
3090  ASSERT_TRUE(item->GetTargetFilePath().empty());
3091  ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
3092
3093  // Respond to the onDeterminingFilename events.
3094  std::string error;
3095  ASSERT_TRUE(ExtensionDownloadsEventRouter::DetermineFilename(
3096      current_browser()->profile(),
3097      false,
3098      GetExtensionId(),
3099      result_id,
3100      base::FilePath(FILE_PATH_LITERAL("42.txt")),
3101      api::FILENAME_CONFLICT_ACTION_UNIQUIFY,
3102      &error));
3103  EXPECT_EQ("", error);
3104
3105  // The download should complete successfully.
3106  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
3107      base::StringPrintf("[{\"id\": %d,"
3108                         "  \"filename\": {"
3109                         "    \"previous\": \"\","
3110                         "    \"current\": \"%s\"}}]",
3111                         result_id,
3112                         GetFilename("42.txt").c_str())));
3113  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
3114      base::StringPrintf("[{\"id\": %d,"
3115                         "  \"state\": {"
3116                         "    \"previous\": \"in_progress\","
3117                         "    \"current\": \"complete\"}}]",
3118                         result_id)));
3119
3120  // Start an incognito download for comparison.
3121  GoOffTheRecord();
3122  result.reset(RunFunctionAndReturnResult(
3123      new DownloadsDownloadFunction(), base::StringPrintf(
3124          "[{\"url\": \"%s\"}]", download_url.c_str())));
3125  ASSERT_TRUE(result.get());
3126  result_id = -1;
3127  ASSERT_TRUE(result->GetAsInteger(&result_id));
3128  item = GetCurrentManager()->GetDownload(result_id);
3129  ASSERT_TRUE(item);
3130  ScopedCancellingItem canceller2(item);
3131  ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
3132
3133  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
3134      base::StringPrintf("[{\"danger\": \"safe\","
3135                         "  \"incognito\": true,"
3136                         "  \"id\": %d,"
3137                         "  \"mime\": \"text/plain\","
3138                         "  \"paused\": false,"
3139                         "  \"url\": \"%s\"}]",
3140                         result_id,
3141                         download_url.c_str())));
3142  // On-Record renderers should not see events for off-record items.
3143  ASSERT_TRUE(WaitFor(
3144      events::kOnDownloadDeterminingFilename,
3145      base::StringPrintf("[{\"id\": %d,"
3146                         "  \"incognito\": true,"
3147                         "  \"filename\":\"slow.txt\"}]",
3148                         result_id)));
3149  ASSERT_TRUE(item->GetTargetFilePath().empty());
3150  ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
3151
3152  // Respond to the onDeterminingFilename.
3153  error = "";
3154  ASSERT_TRUE(ExtensionDownloadsEventRouter::DetermineFilename(
3155      current_browser()->profile(),
3156      false,
3157      GetExtensionId(),
3158      result_id,
3159      base::FilePath(FILE_PATH_LITERAL("5.txt")),
3160      api::FILENAME_CONFLICT_ACTION_UNIQUIFY,
3161      &error));
3162  EXPECT_EQ("", error);
3163
3164  // The download should complete successfully.
3165  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
3166      base::StringPrintf("[{\"id\": %d,"
3167                         "  \"filename\": {"
3168                         "    \"previous\": \"\","
3169                         "    \"current\": \"%s\"}}]",
3170                         result_id,
3171                         GetFilename("5.txt").c_str())));
3172  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
3173      base::StringPrintf("[{\"id\": %d,"
3174                         "  \"state\": {"
3175                         "    \"previous\": \"in_progress\","
3176                         "    \"current\": \"complete\"}}]",
3177                         result_id)));
3178}
3179
3180IN_PROC_BROWSER_TEST_F(
3181    DownloadExtensionTest,
3182    DownloadExtensionTest_OnDeterminingFilename_IncognitoSpanning) {
3183  LoadExtension("downloads_spanning");
3184  ASSERT_TRUE(StartEmbeddedTestServer());
3185  ASSERT_TRUE(test_server()->Start());
3186  std::string download_url = test_server()->GetURL("slow?0").spec();
3187
3188  GoOnTheRecord();
3189  AddFilenameDeterminer();
3190
3191  // There is a single extension renderer that sees both on-record and
3192  // off-record events. The extension functions see the on-record profile with
3193  // include_incognito=true.
3194
3195  // Start an on-record download.
3196  GoOnTheRecord();
3197  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
3198      new DownloadsDownloadFunction(), base::StringPrintf(
3199          "[{\"url\": \"%s\"}]", download_url.c_str())));
3200  ASSERT_TRUE(result.get());
3201  int result_id = -1;
3202  ASSERT_TRUE(result->GetAsInteger(&result_id));
3203  DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
3204  ASSERT_TRUE(item);
3205  ScopedCancellingItem canceller(item);
3206  ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
3207
3208  // Wait for the onCreated and onDeterminingFilename events.
3209  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
3210      base::StringPrintf("[{\"danger\": \"safe\","
3211                          "  \"incognito\": false,"
3212                          "  \"id\": %d,"
3213                          "  \"mime\": \"text/plain\","
3214                          "  \"paused\": false,"
3215                          "  \"url\": \"%s\"}]",
3216                          result_id,
3217                          download_url.c_str())));
3218  ASSERT_TRUE(WaitFor(
3219      events::kOnDownloadDeterminingFilename,
3220      base::StringPrintf("[{\"id\": %d,"
3221                         "  \"incognito\": false,"
3222                         "  \"filename\":\"slow.txt\"}]",
3223                         result_id)));
3224  ASSERT_TRUE(item->GetTargetFilePath().empty());
3225  ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
3226
3227  // Respond to the onDeterminingFilename events.
3228  std::string error;
3229  ASSERT_TRUE(ExtensionDownloadsEventRouter::DetermineFilename(
3230      current_browser()->profile(),
3231      true,
3232      GetExtensionId(),
3233      result_id,
3234      base::FilePath(FILE_PATH_LITERAL("42.txt")),
3235      api::FILENAME_CONFLICT_ACTION_UNIQUIFY,
3236      &error));
3237  EXPECT_EQ("", error);
3238
3239  // The download should complete successfully.
3240  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
3241      base::StringPrintf("[{\"id\": %d,"
3242                         "  \"filename\": {"
3243                         "    \"previous\": \"\","
3244                         "    \"current\": \"%s\"}}]",
3245                         result_id,
3246                         GetFilename("42.txt").c_str())));
3247  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
3248      base::StringPrintf("[{\"id\": %d,"
3249                         "  \"state\": {"
3250                         "    \"previous\": \"in_progress\","
3251                         "    \"current\": \"complete\"}}]",
3252                         result_id)));
3253
3254  // Start an incognito download for comparison.
3255  GoOffTheRecord();
3256  result.reset(RunFunctionAndReturnResult(
3257      new DownloadsDownloadFunction(), base::StringPrintf(
3258          "[{\"url\": \"%s\"}]", download_url.c_str())));
3259  ASSERT_TRUE(result.get());
3260  result_id = -1;
3261  ASSERT_TRUE(result->GetAsInteger(&result_id));
3262  item = GetCurrentManager()->GetDownload(result_id);
3263  ASSERT_TRUE(item);
3264  ScopedCancellingItem canceller2(item);
3265  ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
3266
3267  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
3268      base::StringPrintf("[{\"danger\": \"safe\","
3269                         "  \"incognito\": true,"
3270                         "  \"id\": %d,"
3271                         "  \"mime\": \"text/plain\","
3272                         "  \"paused\": false,"
3273                         "  \"url\": \"%s\"}]",
3274                         result_id,
3275                         download_url.c_str())));
3276  ASSERT_TRUE(WaitFor(
3277      events::kOnDownloadDeterminingFilename,
3278      base::StringPrintf("[{\"id\": %d,"
3279                         "  \"incognito\": true,"
3280                         "  \"filename\":\"slow.txt\"}]",
3281                         result_id)));
3282  ASSERT_TRUE(item->GetTargetFilePath().empty());
3283  ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
3284
3285  // Respond to the onDeterminingFilename.
3286  error = "";
3287  ASSERT_TRUE(ExtensionDownloadsEventRouter::DetermineFilename(
3288      current_browser()->profile(),
3289      true,
3290      GetExtensionId(),
3291      result_id,
3292      base::FilePath(FILE_PATH_LITERAL("42.txt")),
3293      api::FILENAME_CONFLICT_ACTION_UNIQUIFY,
3294      &error));
3295  EXPECT_EQ("", error);
3296
3297  // The download should complete successfully.
3298  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
3299      base::StringPrintf("[{\"id\": %d,"
3300                         "  \"filename\": {"
3301                         "    \"previous\": \"\","
3302                         "    \"current\": \"%s\"}}]",
3303                         result_id,
3304                         GetFilename("42 (1).txt").c_str())));
3305  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
3306      base::StringPrintf("[{\"id\": %d,"
3307                         "  \"state\": {"
3308                         "    \"previous\": \"in_progress\","
3309                         "    \"current\": \"complete\"}}]",
3310                         result_id)));
3311}
3312
3313#if defined(OS_WIN)
3314// This test is very flaky on Win XP and Aura. http://crbug.com/248438
3315#define MAYBE_DownloadExtensionTest_OnDeterminingFilename_InterruptedResume \
3316    DISABLED_DownloadExtensionTest_OnDeterminingFilename_InterruptedResume
3317#else
3318#define MAYBE_DownloadExtensionTest_OnDeterminingFilename_InterruptedResume \
3319    DownloadExtensionTest_OnDeterminingFilename_InterruptedResume
3320#endif
3321
3322// Test download interruption while extensions determining filename. Should not
3323// re-dispatch onDeterminingFilename.
3324IN_PROC_BROWSER_TEST_F(
3325    DownloadExtensionTest,
3326    MAYBE_DownloadExtensionTest_OnDeterminingFilename_InterruptedResume) {
3327  CommandLine::ForCurrentProcess()->AppendSwitch(
3328      switches::kEnableDownloadResumption);
3329  LoadExtension("downloads_split");
3330  ASSERT_TRUE(StartEmbeddedTestServer());
3331  ASSERT_TRUE(test_server()->Start());
3332  GoOnTheRecord();
3333  content::RenderProcessHost* host = AddFilenameDeterminer();
3334
3335  // Start a download.
3336  DownloadItem* item = NULL;
3337  {
3338    DownloadManager* manager = GetCurrentManager();
3339    scoped_ptr<content::DownloadTestObserver> observer(
3340        new JustInProgressDownloadObserver(manager, 1));
3341    ASSERT_EQ(0, manager->InProgressCount());
3342    // Tabs created just for a download are automatically closed, invalidating
3343    // the download's WebContents. Downloads without WebContents cannot be
3344    // resumed. http://crbug.com/225901
3345    ui_test_utils::NavigateToURLWithDisposition(
3346        current_browser(),
3347        GURL(URLRequestSlowDownloadJob::kUnknownSizeUrl),
3348        CURRENT_TAB,
3349        ui_test_utils::BROWSER_TEST_NONE);
3350    observer->WaitForFinished();
3351    EXPECT_EQ(1u, observer->NumDownloadsSeenInState(DownloadItem::IN_PROGRESS));
3352    DownloadManager::DownloadVector items;
3353    manager->GetAllDownloads(&items);
3354    for (DownloadManager::DownloadVector::iterator iter = items.begin();
3355          iter != items.end(); ++iter) {
3356      if ((*iter)->GetState() == DownloadItem::IN_PROGRESS) {
3357        // There should be only one IN_PROGRESS item.
3358        EXPECT_EQ(NULL, item);
3359        item = *iter;
3360      }
3361    }
3362    ASSERT_TRUE(item);
3363  }
3364  ScopedCancellingItem canceller(item);
3365
3366  // Wait for the onCreated and onDeterminingFilename event.
3367  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
3368      base::StringPrintf("[{\"danger\": \"safe\","
3369                         "  \"incognito\": false,"
3370                         "  \"id\": %d,"
3371                         "  \"mime\": \"application/octet-stream\","
3372                         "  \"paused\": false}]",
3373                         item->GetId())));
3374  ASSERT_TRUE(WaitFor(
3375      events::kOnDownloadDeterminingFilename,
3376      base::StringPrintf("[{\"id\": %d,"
3377                         "  \"incognito\": false,"
3378                         "  \"filename\":\"download-unknown-size\"}]",
3379                         item->GetId())));
3380  ASSERT_TRUE(item->GetTargetFilePath().empty());
3381  ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
3382
3383  ClearEvents();
3384  ui_test_utils::NavigateToURLWithDisposition(
3385      current_browser(),
3386      GURL(URLRequestSlowDownloadJob::kErrorDownloadUrl),
3387      NEW_BACKGROUND_TAB,
3388      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
3389
3390  // Errors caught before filename determination are delayed until after
3391  // filename determination.
3392  std::string error;
3393  ASSERT_TRUE(ExtensionDownloadsEventRouter::DetermineFilename(
3394      current_browser()->profile(),
3395      false,
3396      GetExtensionId(),
3397      item->GetId(),
3398      base::FilePath(FILE_PATH_LITERAL("42.txt")),
3399      api::FILENAME_CONFLICT_ACTION_UNIQUIFY,
3400      &error)) << error;
3401  EXPECT_EQ("", error);
3402  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
3403      base::StringPrintf("[{\"id\": %d,"
3404                         "  \"filename\": {"
3405                         "    \"previous\": \"\","
3406                         "    \"current\": \"%s\"}}]",
3407                         item->GetId(),
3408                         GetFilename("42.txt").c_str())));
3409
3410  content::DownloadUpdatedObserver interrupted(item, base::Bind(
3411      ItemIsInterrupted));
3412  ASSERT_TRUE(interrupted.WaitForEvent());
3413  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
3414      base::StringPrintf("[{\"id\": %d,"
3415                         "  \"error\":{\"current\":\"NETWORK_FAILED\"},"
3416                         "  \"state\":{"
3417                         "    \"previous\":\"in_progress\","
3418                         "    \"current\":\"interrupted\"}}]",
3419                         item->GetId())));
3420
3421  ClearEvents();
3422  // Downloads that are restarted on resumption trigger another download target
3423  // determination.
3424  RemoveFilenameDeterminer(host);
3425  item->Resume();
3426
3427  // Errors caught before filename determination is complete are delayed until
3428  // after filename determination so that, on resumption, filename determination
3429  // does not need to be re-done. So, there will not be a second
3430  // onDeterminingFilename event.
3431
3432  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
3433      base::StringPrintf("[{\"id\": %d,"
3434                         "  \"error\":{\"previous\":\"NETWORK_FAILED\"},"
3435                         "  \"state\":{"
3436                         "    \"previous\":\"interrupted\","
3437                         "    \"current\":\"in_progress\"}}]",
3438                         item->GetId())));
3439
3440  ClearEvents();
3441  FinishPendingSlowDownloads();
3442
3443  // The download should complete successfully.
3444  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
3445      base::StringPrintf("[{\"id\": %d,"
3446                         "  \"state\": {"
3447                         "    \"previous\": \"in_progress\","
3448                         "    \"current\": \"complete\"}}]",
3449                         item->GetId())));
3450}
3451
3452IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
3453                       DownloadExtensionTest_SetShelfEnabled) {
3454  LoadExtension("downloads_split");
3455  EXPECT_TRUE(RunFunction(new DownloadsSetShelfEnabledFunction(), "[false]"));
3456  EXPECT_FALSE(DownloadServiceFactory::GetForBrowserContext(
3457      browser()->profile())->IsShelfEnabled());
3458  EXPECT_TRUE(RunFunction(new DownloadsSetShelfEnabledFunction(), "[true]"));
3459  EXPECT_TRUE(DownloadServiceFactory::GetForBrowserContext(
3460      browser()->profile())->IsShelfEnabled());
3461  // TODO(benjhayden) Test that existing shelves are hidden.
3462  // TODO(benjhayden) Test multiple extensions.
3463  // TODO(benjhayden) Test disabling extensions.
3464  // TODO(benjhayden) Test that browsers associated with other profiles are not
3465  // affected.
3466  // TODO(benjhayden) Test incognito.
3467}
3468
3469// TODO(benjhayden) Figure out why DisableExtension() does not fire
3470// OnListenerRemoved.
3471
3472// TODO(benjhayden) Test that the shelf is shown for download() both with and
3473// without a WebContents.
3474
3475class DownloadsApiTest : public ExtensionApiTest {
3476 public:
3477  DownloadsApiTest() {}
3478  virtual ~DownloadsApiTest() {}
3479 private:
3480  DISALLOW_COPY_AND_ASSIGN(DownloadsApiTest);
3481};
3482
3483
3484IN_PROC_BROWSER_TEST_F(DownloadsApiTest, DownloadsApiTest) {
3485  ASSERT_TRUE(RunExtensionTest("downloads")) << message_;
3486}
3487
3488TEST(DownloadInterruptReasonEnumsSynced,
3489     DownloadInterruptReasonEnumsSynced) {
3490#define INTERRUPT_REASON(name, value) \
3491  EXPECT_EQ(InterruptReasonContentToExtension( \
3492      content::DOWNLOAD_INTERRUPT_REASON_##name), \
3493      api::INTERRUPT_REASON_##name); \
3494  EXPECT_EQ(InterruptReasonExtensionToContent( \
3495      api::INTERRUPT_REASON_##name), \
3496      content::DOWNLOAD_INTERRUPT_REASON_##name);
3497#include "content/public/browser/download_interrupt_reason_values.h"
3498#undef INTERRUPT_REASON
3499}
3500
3501TEST(ExtensionDetermineDownloadFilenameInternal,
3502     ExtensionDetermineDownloadFilenameInternal) {
3503
3504  std::string winner_id;
3505  base::FilePath filename;
3506  extensions::api::downloads::FilenameConflictAction conflict_action =
3507    api::FILENAME_CONFLICT_ACTION_UNIQUIFY;
3508  extensions::ExtensionWarningSet warnings;
3509
3510  // Empty incumbent determiner
3511  warnings.clear();
3512  ExtensionDownloadsEventRouter::DetermineFilenameInternal(
3513      base::FilePath(FILE_PATH_LITERAL("a")),
3514      api::FILENAME_CONFLICT_ACTION_OVERWRITE,
3515      "suggester",
3516      base::Time::Now(),
3517      "",
3518      base::Time(),
3519      &winner_id,
3520      &filename,
3521      &conflict_action,
3522      &warnings);
3523  EXPECT_EQ("suggester", winner_id);
3524  EXPECT_EQ(FILE_PATH_LITERAL("a"), filename.value());
3525  EXPECT_EQ(api::FILENAME_CONFLICT_ACTION_OVERWRITE, conflict_action);
3526  EXPECT_TRUE(warnings.empty());
3527
3528  // Incumbent wins
3529  warnings.clear();
3530  ExtensionDownloadsEventRouter::DetermineFilenameInternal(
3531      base::FilePath(FILE_PATH_LITERAL("b")),
3532      api::FILENAME_CONFLICT_ACTION_PROMPT,
3533      "suggester",
3534      base::Time::Now() - base::TimeDelta::FromDays(1),
3535      "incumbent",
3536      base::Time::Now(),
3537      &winner_id,
3538      &filename,
3539      &conflict_action,
3540      &warnings);
3541  EXPECT_EQ("incumbent", winner_id);
3542  EXPECT_EQ(FILE_PATH_LITERAL("a"), filename.value());
3543  EXPECT_EQ(api::FILENAME_CONFLICT_ACTION_OVERWRITE, conflict_action);
3544  EXPECT_FALSE(warnings.empty());
3545  EXPECT_EQ(extensions::ExtensionWarning::kDownloadFilenameConflict,
3546            warnings.begin()->warning_type());
3547  EXPECT_EQ("suggester", warnings.begin()->extension_id());
3548
3549  // Suggester wins
3550  warnings.clear();
3551  ExtensionDownloadsEventRouter::DetermineFilenameInternal(
3552      base::FilePath(FILE_PATH_LITERAL("b")),
3553      api::FILENAME_CONFLICT_ACTION_PROMPT,
3554      "suggester",
3555      base::Time::Now(),
3556      "incumbent",
3557      base::Time::Now() - base::TimeDelta::FromDays(1),
3558      &winner_id,
3559      &filename,
3560      &conflict_action,
3561      &warnings);
3562  EXPECT_EQ("suggester", winner_id);
3563  EXPECT_EQ(FILE_PATH_LITERAL("b"), filename.value());
3564  EXPECT_EQ(api::FILENAME_CONFLICT_ACTION_PROMPT, conflict_action);
3565  EXPECT_FALSE(warnings.empty());
3566  EXPECT_EQ(extensions::ExtensionWarning::kDownloadFilenameConflict,
3567            warnings.begin()->warning_type());
3568  EXPECT_EQ("incumbent", warnings.begin()->extension_id());
3569}
3570