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