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