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