Update To 11.40.268.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/files/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/test/download_test_observer.h"
43 #include "content/test/net/url_request_slow_download_job.h"
44 #include "extensions/browser/event_router.h"
45 #include "extensions/browser/notification_types.h"
46 #include "net/base/data_url.h"
47 #include "net/base/net_util.h"
48 #include "net/url_request/url_request.h"
49 #include "net/url_request/url_request_context.h"
50 #include "net/url_request/url_request_job.h"
51 #include "net/url_request/url_request_job_factory.h"
52 #include "net/url_request/url_request_job_factory_impl.h"
53 #include "storage/browser/fileapi/file_system_context.h"
54 #include "storage/browser/fileapi/file_system_operation_runner.h"
55 #include "storage/browser/fileapi/file_system_url.h"
56 #include "ui/base/page_transition_types.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   ~DownloadsEventsListener() override {
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   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         ui::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         ui::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   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           ui::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   ~MockIconExtractorImpl() override {}
621
622   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(storage::FileSystemContext* context,
703                                    const storage::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       storage::FileSystemContext* context,
739       const storage::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   ~JustInProgressDownloadObserver() override {}
762
763  private:
764   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* const 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::kInvalidHeaderUnsafe,
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 // Tests that invalid header names and values are rejected.
1621 IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
1622                        DownloadExtensionTest_Download_InvalidHeaders) {
1623   LoadExtension("downloads_split");
1624   ASSERT_TRUE(StartEmbeddedTestServer());
1625   ASSERT_TRUE(test_server()->Start());
1626   GoOnTheRecord();
1627   std::string download_url = test_server()->GetURL("slow?0").spec();
1628   EXPECT_STREQ(errors::kInvalidHeaderName,
1629                RunFunctionAndReturnError(new DownloadsDownloadFunction(),
1630                                          base::StringPrintf(
1631       "[{\"url\": \"%s\","
1632       "  \"filename\": \"unsafe-header-crlf.txt\","
1633       "  \"headers\": [{"
1634       "    \"name\": \"Header\\r\\nSec-Spoof: Hey\\r\\nX-Split:X\","
1635       "    \"value\": \"unsafe\"}]}]",
1636       download_url.c_str())).c_str());
1637
1638   EXPECT_STREQ(errors::kInvalidHeaderValue,
1639                RunFunctionAndReturnError(new DownloadsDownloadFunction(),
1640                                          base::StringPrintf(
1641       "[{\"url\": \"%s\","
1642       "  \"filename\": \"unsafe-header-crlf.txt\","
1643       "  \"headers\": [{"
1644       "    \"name\": \"Invalid-value\","
1645       "    \"value\": \"hey\\r\\nSec-Spoof: Hey\"}]}]",
1646       download_url.c_str())).c_str());
1647 }
1648
1649 #if defined(OS_WIN)
1650 #define MAYBE_DownloadExtensionTest_Download_Subdirectory\
1651         DISABLED_DownloadExtensionTest_Download_Subdirectory
1652 #else
1653 #define MAYBE_DownloadExtensionTest_Download_Subdirectory\
1654         DownloadExtensionTest_Download_Subdirectory
1655 #endif
1656 IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
1657                        MAYBE_DownloadExtensionTest_Download_Subdirectory) {
1658   LoadExtension("downloads_split");
1659   ASSERT_TRUE(StartEmbeddedTestServer());
1660   ASSERT_TRUE(test_server()->Start());
1661   std::string download_url = test_server()->GetURL("slow?0").spec();
1662   GoOnTheRecord();
1663
1664   scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
1665       new DownloadsDownloadFunction(), base::StringPrintf(
1666           "[{\"url\": \"%s\","
1667           "  \"filename\": \"sub/dir/ect/ory.txt\"}]",
1668           download_url.c_str())));
1669   ASSERT_TRUE(result.get());
1670   int result_id = -1;
1671   ASSERT_TRUE(result->GetAsInteger(&result_id));
1672   DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
1673   ASSERT_TRUE(item);
1674   ScopedCancellingItem canceller(item);
1675   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
1676
1677   ASSERT_TRUE(WaitFor(downloads::OnCreated::kEventName,
1678                       base::StringPrintf(
1679                           "[{\"danger\": \"safe\","
1680                           "  \"incognito\": false,"
1681                           "  \"mime\": \"text/plain\","
1682                           "  \"paused\": false,"
1683                           "  \"url\": \"%s\"}]",
1684                           download_url.c_str())));
1685   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
1686                       base::StringPrintf(
1687                           "[{\"id\": %d,"
1688                           "  \"filename\": {"
1689                           "    \"previous\": \"\","
1690                           "    \"current\": \"%s\"}}]",
1691                           result_id,
1692                           GetFilename("sub/dir/ect/ory.txt").c_str())));
1693   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
1694                       base::StringPrintf(
1695                           "[{\"id\": %d,"
1696                           "  \"state\": {"
1697                           "    \"previous\": \"in_progress\","
1698                           "    \"current\": \"complete\"}}]",
1699                           result_id)));
1700 }
1701
1702 // Test that invalid filenames are disallowed.
1703 IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
1704                        DownloadExtensionTest_Download_InvalidFilename) {
1705   LoadExtension("downloads_split");
1706   ASSERT_TRUE(StartEmbeddedTestServer());
1707   ASSERT_TRUE(test_server()->Start());
1708   std::string download_url = test_server()->GetURL("slow?0").spec();
1709   GoOnTheRecord();
1710
1711   EXPECT_STREQ(errors::kInvalidFilename,
1712                 RunFunctionAndReturnError(new DownloadsDownloadFunction(),
1713                                           base::StringPrintf(
1714       "[{\"url\": \"%s\","
1715       "  \"filename\": \"../../../../../etc/passwd\"}]",
1716       download_url.c_str())).c_str());
1717 }
1718
1719 // flaky on mac: crbug.com/392288
1720 #if defined(OS_MACOSX)
1721 #define MAYBE_DownloadExtensionTest_Download_InvalidURLs \
1722         DISABLED_DownloadExtensionTest_Download_InvalidURLs
1723 #else
1724 #define MAYBE_DownloadExtensionTest_Download_InvalidURLs \
1725         DownloadExtensionTest_Download_InvalidURLs
1726 #endif
1727
1728 // Test that downloading invalid URLs immediately returns kInvalidURLError.
1729 IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
1730                        MAYBE_DownloadExtensionTest_Download_InvalidURLs) {
1731   LoadExtension("downloads_split");
1732   GoOnTheRecord();
1733
1734   static const char* const kInvalidURLs[] = {
1735     "foo bar",
1736     "../hello",
1737     "/hello",
1738     "http://",
1739     "#frag",
1740     "foo/bar.html#frag",
1741     "google.com/",
1742   };
1743
1744   for (size_t index = 0; index < arraysize(kInvalidURLs); ++index) {
1745     EXPECT_STREQ(errors::kInvalidURL,
1746                   RunFunctionAndReturnError(new DownloadsDownloadFunction(),
1747                                             base::StringPrintf(
1748         "[{\"url\": \"%s\"}]", kInvalidURLs[index])).c_str())
1749       << kInvalidURLs[index];
1750   }
1751
1752   EXPECT_STREQ("NETWORK_INVALID_REQUEST", RunFunctionAndReturnError(
1753       new DownloadsDownloadFunction(),
1754       "[{\"url\": \"javascript:document.write(\\\"hello\\\");\"}]").c_str());
1755   EXPECT_STREQ("NETWORK_INVALID_REQUEST", RunFunctionAndReturnError(
1756       new DownloadsDownloadFunction(),
1757       "[{\"url\": \"javascript:return false;\"}]").c_str());
1758   EXPECT_STREQ("NETWORK_FAILED", RunFunctionAndReturnError(
1759       new DownloadsDownloadFunction(),
1760       "[{\"url\": \"ftp://example.com/example.txt\"}]").c_str());
1761 }
1762
1763 // TODO(benjhayden): Set up a test ftp server, add ftp://localhost* to
1764 // permissions, test downloading from ftp.
1765
1766 // Valid URLs plus fragments are still valid URLs.
1767 IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
1768                        DownloadExtensionTest_Download_URLFragment) {
1769   LoadExtension("downloads_split");
1770   ASSERT_TRUE(StartEmbeddedTestServer());
1771   ASSERT_TRUE(test_server()->Start());
1772   std::string download_url = test_server()->GetURL("slow?0#fragment").spec();
1773   GoOnTheRecord();
1774
1775   scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
1776       new DownloadsDownloadFunction(), base::StringPrintf(
1777           "[{\"url\": \"%s\"}]", download_url.c_str())));
1778   ASSERT_TRUE(result.get());
1779   int result_id = -1;
1780   ASSERT_TRUE(result->GetAsInteger(&result_id));
1781   DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
1782   ASSERT_TRUE(item);
1783   ScopedCancellingItem canceller(item);
1784   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
1785
1786   ASSERT_TRUE(WaitFor(downloads::OnCreated::kEventName,
1787                       base::StringPrintf(
1788                           "[{\"danger\": \"safe\","
1789                           "  \"incognito\": false,"
1790                           "  \"mime\": \"text/plain\","
1791                           "  \"paused\": false,"
1792                           "  \"url\": \"%s\"}]",
1793                           download_url.c_str())));
1794   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
1795                       base::StringPrintf(
1796                           "[{\"id\": %d,"
1797                           "  \"filename\": {"
1798                           "    \"previous\": \"\","
1799                           "    \"current\": \"%s\"}}]",
1800                           result_id,
1801                           GetFilename("slow.txt").c_str())));
1802   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
1803                       base::StringPrintf(
1804                           "[{\"id\": %d,"
1805                           "  \"state\": {"
1806                           "    \"previous\": \"in_progress\","
1807                           "    \"current\": \"complete\"}}]",
1808                           result_id)));
1809 }
1810
1811 // conflictAction may be specified without filename.
1812 IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
1813                        DownloadExtensionTest_Download_ConflictAction) {
1814   static char kFilename[] = "download.txt";
1815   LoadExtension("downloads_split");
1816   std::string download_url = "data:text/plain,hello";
1817   GoOnTheRecord();
1818
1819   scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
1820       new DownloadsDownloadFunction(), base::StringPrintf(
1821       "[{\"url\": \"%s\"}]", download_url.c_str())));
1822   ASSERT_TRUE(result.get());
1823   int result_id = -1;
1824   ASSERT_TRUE(result->GetAsInteger(&result_id));
1825   DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
1826   ASSERT_TRUE(item);
1827   ScopedCancellingItem canceller(item);
1828   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
1829
1830   ASSERT_TRUE(WaitFor(downloads::OnCreated::kEventName,
1831                       base::StringPrintf(
1832                           "[{\"danger\": \"safe\","
1833                           "  \"incognito\": false,"
1834                           "  \"mime\": \"text/plain\","
1835                           "  \"paused\": false,"
1836                           "  \"url\": \"%s\"}]",
1837                           download_url.c_str())));
1838   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
1839                       base::StringPrintf(
1840                           "[{\"id\": %d,"
1841                           "  \"filename\": {"
1842                           "    \"previous\": \"\","
1843                           "    \"current\": \"%s\"}}]",
1844                           result_id,
1845                           GetFilename(kFilename).c_str())));
1846   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
1847                       base::StringPrintf(
1848                           "[{\"id\": %d,"
1849                           "  \"state\": {"
1850                           "    \"previous\": \"in_progress\","
1851                           "    \"current\": \"complete\"}}]",
1852                           result_id)));
1853
1854   result.reset(RunFunctionAndReturnResult(
1855       new DownloadsDownloadFunction(), base::StringPrintf(
1856           "[{\"url\": \"%s\",  \"conflictAction\": \"overwrite\"}]",
1857           download_url.c_str())));
1858   ASSERT_TRUE(result.get());
1859   result_id = -1;
1860   ASSERT_TRUE(result->GetAsInteger(&result_id));
1861   item = GetCurrentManager()->GetDownload(result_id);
1862   ASSERT_TRUE(item);
1863   ScopedCancellingItem canceller2(item);
1864   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
1865
1866   ASSERT_TRUE(WaitFor(downloads::OnCreated::kEventName,
1867                       base::StringPrintf(
1868                           "[{\"danger\": \"safe\","
1869                           "  \"incognito\": false,"
1870                           "  \"mime\": \"text/plain\","
1871                           "  \"paused\": false,"
1872                           "  \"url\": \"%s\"}]",
1873                           download_url.c_str())));
1874   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
1875                       base::StringPrintf(
1876                           "[{\"id\": %d,"
1877                           "  \"filename\": {"
1878                           "    \"previous\": \"\","
1879                           "    \"current\": \"%s\"}}]",
1880                           result_id,
1881                           GetFilename(kFilename).c_str())));
1882   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
1883                       base::StringPrintf(
1884                           "[{\"id\": %d,"
1885                           "  \"state\": {"
1886                           "    \"previous\": \"in_progress\","
1887                           "    \"current\": \"complete\"}}]",
1888                           result_id)));
1889 }
1890
1891 // Valid data URLs are valid URLs.
1892 IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
1893                        DownloadExtensionTest_Download_DataURL) {
1894   LoadExtension("downloads_split");
1895   std::string download_url = "data:text/plain,hello";
1896   GoOnTheRecord();
1897
1898   scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
1899         new DownloadsDownloadFunction(), base::StringPrintf(
1900       "[{\"url\": \"%s\","
1901       "  \"filename\": \"data.txt\"}]", download_url.c_str())));
1902   ASSERT_TRUE(result.get());
1903   int result_id = -1;
1904   ASSERT_TRUE(result->GetAsInteger(&result_id));
1905   DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
1906   ASSERT_TRUE(item);
1907   ScopedCancellingItem canceller(item);
1908   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
1909
1910   ASSERT_TRUE(WaitFor(downloads::OnCreated::kEventName,
1911                       base::StringPrintf(
1912                           "[{\"danger\": \"safe\","
1913                           "  \"incognito\": false,"
1914                           "  \"mime\": \"text/plain\","
1915                           "  \"paused\": false,"
1916                           "  \"url\": \"%s\"}]",
1917                           download_url.c_str())));
1918   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
1919                       base::StringPrintf(
1920                           "[{\"id\": %d,"
1921                           "  \"filename\": {"
1922                           "    \"previous\": \"\","
1923                           "    \"current\": \"%s\"}}]",
1924                           result_id,
1925                           GetFilename("data.txt").c_str())));
1926   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
1927                       base::StringPrintf(
1928                           "[{\"id\": %d,"
1929                           "  \"state\": {"
1930                           "    \"previous\": \"in_progress\","
1931                           "    \"current\": \"complete\"}}]",
1932                           result_id)));
1933 }
1934
1935 // Valid file URLs are valid URLs.
1936 #if defined(OS_WIN)
1937 // Disabled due to crbug.com/175711
1938 #define MAYBE_DownloadExtensionTest_Download_File \
1939         DISABLED_DownloadExtensionTest_Download_File
1940 #else
1941 #define MAYBE_DownloadExtensionTest_Download_File \
1942         DownloadExtensionTest_Download_File
1943 #endif
1944 IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
1945                        MAYBE_DownloadExtensionTest_Download_File) {
1946   GoOnTheRecord();
1947   LoadExtension("downloads_split");
1948   std::string download_url = "file:///";
1949 #if defined(OS_WIN)
1950   download_url += "C:/";
1951 #endif
1952
1953   scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
1954         new DownloadsDownloadFunction(), base::StringPrintf(
1955       "[{\"url\": \"%s\","
1956       "  \"filename\": \"file.txt\"}]", download_url.c_str())));
1957   ASSERT_TRUE(result.get());
1958   int result_id = -1;
1959   ASSERT_TRUE(result->GetAsInteger(&result_id));
1960   DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
1961   ASSERT_TRUE(item);
1962   ScopedCancellingItem canceller(item);
1963   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
1964
1965   ASSERT_TRUE(WaitFor(downloads::OnCreated::kEventName,
1966                       base::StringPrintf(
1967                           "[{\"danger\": \"safe\","
1968                           "  \"incognito\": false,"
1969                           "  \"mime\": \"text/html\","
1970                           "  \"paused\": false,"
1971                           "  \"url\": \"%s\"}]",
1972                           download_url.c_str())));
1973   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
1974                       base::StringPrintf(
1975                           "[{\"id\": %d,"
1976                           "  \"filename\": {"
1977                           "    \"previous\": \"\","
1978                           "    \"current\": \"%s\"}}]",
1979                           result_id,
1980                           GetFilename("file.txt").c_str())));
1981   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
1982                       base::StringPrintf(
1983                           "[{\"id\": %d,"
1984                           "  \"state\": {"
1985                           "    \"previous\": \"in_progress\","
1986                           "    \"current\": \"complete\"}}]",
1987                           result_id)));
1988 }
1989
1990 // Test that auth-basic-succeed would fail if the resource requires the
1991 // Authorization header and chrome fails to propagate it back to the server.
1992 // This tests both that testserver.py does not succeed when it should fail as
1993 // well as how the downloads extension API exposes the failure to extensions.
1994 IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
1995                        DownloadExtensionTest_Download_AuthBasic_Fail) {
1996   LoadExtension("downloads_split");
1997   ASSERT_TRUE(StartEmbeddedTestServer());
1998   ASSERT_TRUE(test_server()->Start());
1999   std::string download_url = test_server()->GetURL("auth-basic").spec();
2000   GoOnTheRecord();
2001
2002   scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
2003         new DownloadsDownloadFunction(), base::StringPrintf(
2004       "[{\"url\": \"%s\","
2005       "  \"filename\": \"auth-basic-fail.txt\"}]",
2006       download_url.c_str())));
2007   ASSERT_TRUE(result.get());
2008   int result_id = -1;
2009   ASSERT_TRUE(result->GetAsInteger(&result_id));
2010   DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
2011   ASSERT_TRUE(item);
2012   ScopedCancellingItem canceller(item);
2013   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
2014
2015   ASSERT_TRUE(WaitForInterruption(
2016       item,
2017       content::DOWNLOAD_INTERRUPT_REASON_SERVER_UNAUTHORIZED,
2018       base::StringPrintf("[{\"danger\": \"safe\","
2019                          "  \"incognito\": false,"
2020                          "  \"mime\": \"text/html\","
2021                          "  \"paused\": false,"
2022                          "  \"url\": \"%s\"}]",
2023                          download_url.c_str())));
2024 }
2025
2026 // Test that DownloadsDownloadFunction propagates |headers| to the URLRequest.
2027 IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
2028                        DownloadExtensionTest_Download_Headers) {
2029   LoadExtension("downloads_split");
2030   ASSERT_TRUE(StartEmbeddedTestServer());
2031   ASSERT_TRUE(test_server()->Start());
2032   std::string download_url = test_server()->GetURL("files/downloads/"
2033       "a_zip_file.zip?expected_headers=Foo:bar&expected_headers=Qx:yo").spec();
2034   GoOnTheRecord();
2035
2036   scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
2037         new DownloadsDownloadFunction(), base::StringPrintf(
2038       "[{\"url\": \"%s\","
2039       "  \"filename\": \"headers-succeed.txt\","
2040       "  \"headers\": ["
2041       "    {\"name\": \"Foo\", \"value\": \"bar\"},"
2042       "    {\"name\": \"Qx\", \"value\":\"yo\"}]}]",
2043       download_url.c_str())));
2044   ASSERT_TRUE(result.get());
2045   int result_id = -1;
2046   ASSERT_TRUE(result->GetAsInteger(&result_id));
2047   DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
2048   ASSERT_TRUE(item);
2049   ScopedCancellingItem canceller(item);
2050   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
2051
2052   ASSERT_TRUE(WaitFor(downloads::OnCreated::kEventName,
2053                       base::StringPrintf(
2054                           "[{\"danger\": \"safe\","
2055                           "  \"incognito\": false,"
2056                           "  \"mime\": \"application/octet-stream\","
2057                           "  \"paused\": false,"
2058                           "  \"url\": \"%s\"}]",
2059                           download_url.c_str())));
2060   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
2061                       base::StringPrintf(
2062                           "[{\"id\": %d,"
2063                           "  \"filename\": {"
2064                           "    \"previous\": \"\","
2065                           "    \"current\": \"%s\"}}]",
2066                           result_id,
2067                           GetFilename("headers-succeed.txt").c_str())));
2068   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
2069                       base::StringPrintf(
2070                           "[{\"id\": %d,"
2071                           "  \"state\": {"
2072                           "    \"previous\": \"in_progress\","
2073                           "    \"current\": \"complete\"}}]",
2074                           result_id)));
2075 }
2076
2077 // Test that headers-succeed would fail if the resource requires the headers and
2078 // chrome fails to propagate them back to the server.  This tests both that
2079 // testserver.py does not succeed when it should fail as well as how the
2080 // downloads extension api exposes the failure to extensions.
2081 IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
2082                        DownloadExtensionTest_Download_Headers_Fail) {
2083   LoadExtension("downloads_split");
2084   ASSERT_TRUE(StartEmbeddedTestServer());
2085   ASSERT_TRUE(test_server()->Start());
2086   std::string download_url = test_server()->GetURL("files/downloads/"
2087       "a_zip_file.zip?expected_headers=Foo:bar&expected_headers=Qx:yo").spec();
2088   GoOnTheRecord();
2089
2090   scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
2091         new DownloadsDownloadFunction(), base::StringPrintf(
2092       "[{\"url\": \"%s\","
2093       "  \"filename\": \"headers-fail.txt\"}]",
2094       download_url.c_str())));
2095   ASSERT_TRUE(result.get());
2096   int result_id = -1;
2097   ASSERT_TRUE(result->GetAsInteger(&result_id));
2098   DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
2099   ASSERT_TRUE(item);
2100   ScopedCancellingItem canceller(item);
2101   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
2102
2103   ASSERT_TRUE(WaitForInterruption(
2104       item,
2105       content::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT,
2106       base::StringPrintf("[{\"danger\": \"safe\","
2107                          "  \"incognito\": false,"
2108                          "  \"bytesReceived\": 0.0,"
2109                          "  \"fileSize\": 0.0,"
2110                          "  \"mime\": \"\","
2111                          "  \"paused\": false,"
2112                          "  \"url\": \"%s\"}]",
2113                          download_url.c_str())));
2114 }
2115
2116 // Test that DownloadsDownloadFunction propagates the Authorization header
2117 // correctly.
2118 IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
2119                        DownloadExtensionTest_Download_AuthBasic) {
2120   LoadExtension("downloads_split");
2121   ASSERT_TRUE(StartEmbeddedTestServer());
2122   ASSERT_TRUE(test_server()->Start());
2123   std::string download_url = test_server()->GetURL("auth-basic").spec();
2124   // This is just base64 of 'username:secret'.
2125   static const char kAuthorization[] = "dXNlcm5hbWU6c2VjcmV0";
2126   GoOnTheRecord();
2127
2128   scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
2129         new DownloadsDownloadFunction(), base::StringPrintf(
2130       "[{\"url\": \"%s\","
2131       "  \"filename\": \"auth-basic-succeed.txt\","
2132       "  \"headers\": [{"
2133       "    \"name\": \"Authorization\","
2134       "    \"value\": \"Basic %s\"}]}]",
2135       download_url.c_str(), kAuthorization)));
2136   ASSERT_TRUE(result.get());
2137   int result_id = -1;
2138   ASSERT_TRUE(result->GetAsInteger(&result_id));
2139   DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
2140   ASSERT_TRUE(item);
2141   ScopedCancellingItem canceller(item);
2142   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
2143
2144   ASSERT_TRUE(WaitFor(downloads::OnCreated::kEventName,
2145                       base::StringPrintf(
2146                           "[{\"danger\": \"safe\","
2147                           "  \"incognito\": false,"
2148                           "  \"bytesReceived\": 0.0,"
2149                           "  \"fileSize\": 0.0,"
2150                           "  \"mime\": \"text/html\","
2151                           "  \"paused\": false,"
2152                           "  \"url\": \"%s\"}]",
2153                           download_url.c_str())));
2154   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
2155                       base::StringPrintf(
2156                           "[{\"id\": %d,"
2157                           "  \"state\": {"
2158                           "    \"previous\": \"in_progress\","
2159                           "    \"current\": \"complete\"}}]",
2160                           result_id)));
2161 }
2162
2163 // Test that DownloadsDownloadFunction propagates the |method| and |body|
2164 // parameters to the URLRequest.
2165 IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
2166                        DownloadExtensionTest_Download_Post) {
2167   LoadExtension("downloads_split");
2168   ASSERT_TRUE(StartEmbeddedTestServer());
2169   ASSERT_TRUE(test_server()->Start());
2170   std::string download_url = test_server()->GetURL("files/post/downloads/"
2171       "a_zip_file.zip?expected_body=BODY").spec();
2172   GoOnTheRecord();
2173
2174   scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
2175         new DownloadsDownloadFunction(), base::StringPrintf(
2176       "[{\"url\": \"%s\","
2177       "  \"filename\": \"post-succeed.txt\","
2178       "  \"method\": \"POST\","
2179       "  \"body\": \"BODY\"}]",
2180       download_url.c_str())));
2181   ASSERT_TRUE(result.get());
2182   int result_id = -1;
2183   ASSERT_TRUE(result->GetAsInteger(&result_id));
2184   DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
2185   ASSERT_TRUE(item);
2186   ScopedCancellingItem canceller(item);
2187   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
2188
2189   ASSERT_TRUE(WaitFor(downloads::OnCreated::kEventName,
2190                       base::StringPrintf(
2191                           "[{\"danger\": \"safe\","
2192                           "  \"incognito\": false,"
2193                           "  \"mime\": \"application/octet-stream\","
2194                           "  \"paused\": false,"
2195                           "  \"url\": \"%s\"}]",
2196                           download_url.c_str())));
2197   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
2198                       base::StringPrintf(
2199                           "[{\"id\": %d,"
2200                           "  \"filename\": {"
2201                           "    \"previous\": \"\","
2202                           "    \"current\": \"%s\"}}]",
2203                           result_id,
2204                           GetFilename("post-succeed.txt").c_str())));
2205   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
2206                       base::StringPrintf(
2207                           "[{\"id\": %d,"
2208                           "  \"state\": {"
2209                           "    \"previous\": \"in_progress\","
2210                           "    \"current\": \"complete\"}}]",
2211                           result_id)));
2212 }
2213
2214 // Test that downloadPostSuccess would fail if the resource requires the POST
2215 // method, and chrome fails to propagate the |method| parameter back to the
2216 // server. This tests both that testserver.py does not succeed when it should
2217 // fail, and this tests how the downloads extension api exposes the failure to
2218 // extensions.
2219 IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
2220                        DownloadExtensionTest_Download_Post_Get) {
2221   LoadExtension("downloads_split");
2222   ASSERT_TRUE(StartEmbeddedTestServer());
2223   ASSERT_TRUE(test_server()->Start());
2224   std::string download_url = test_server()->GetURL("files/post/downloads/"
2225       "a_zip_file.zip?expected_body=BODY").spec();
2226   GoOnTheRecord();
2227
2228   scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
2229         new DownloadsDownloadFunction(), base::StringPrintf(
2230       "[{\"url\": \"%s\","
2231       "  \"body\": \"BODY\","
2232       "  \"filename\": \"post-get.txt\"}]",
2233       download_url.c_str())));
2234   ASSERT_TRUE(result.get());
2235   int result_id = -1;
2236   ASSERT_TRUE(result->GetAsInteger(&result_id));
2237   DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
2238   ASSERT_TRUE(item);
2239   ScopedCancellingItem canceller(item);
2240   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
2241
2242   ASSERT_TRUE(WaitForInterruption(
2243       item,
2244       content::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT,
2245       base::StringPrintf("[{\"danger\": \"safe\","
2246                          "  \"incognito\": false,"
2247                          "  \"mime\": \"\","
2248                          "  \"paused\": false,"
2249                          "  \"id\": %d,"
2250                          "  \"url\": \"%s\"}]",
2251                          result_id,
2252                          download_url.c_str())));
2253 }
2254
2255 // Test that downloadPostSuccess would fail if the resource requires the POST
2256 // method, and chrome fails to propagate the |body| parameter back to the
2257 // server. This tests both that testserver.py does not succeed when it should
2258 // fail, and this tests how the downloads extension api exposes the failure to
2259 // extensions.
2260 IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
2261                        DownloadExtensionTest_Download_Post_NoBody) {
2262   LoadExtension("downloads_split");
2263   ASSERT_TRUE(StartEmbeddedTestServer());
2264   ASSERT_TRUE(test_server()->Start());
2265   std::string download_url = test_server()->GetURL("files/post/downloads/"
2266       "a_zip_file.zip?expected_body=BODY").spec();
2267   GoOnTheRecord();
2268
2269   scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
2270       new DownloadsDownloadFunction(), base::StringPrintf(
2271       "[{\"url\": \"%s\","
2272       "  \"method\": \"POST\","
2273       "  \"filename\": \"post-nobody.txt\"}]",
2274       download_url.c_str())));
2275   ASSERT_TRUE(result.get());
2276   int result_id = -1;
2277   ASSERT_TRUE(result->GetAsInteger(&result_id));
2278   DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
2279   ASSERT_TRUE(item);
2280   ScopedCancellingItem canceller(item);
2281   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
2282
2283   ASSERT_TRUE(WaitForInterruption(
2284       item,
2285       content::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT,
2286       base::StringPrintf("[{\"danger\": \"safe\","
2287                          "  \"incognito\": false,"
2288                          "  \"mime\": \"\","
2289                          "  \"paused\": false,"
2290                          "  \"id\": %d,"
2291                          "  \"url\": \"%s\"}]",
2292                          result_id,
2293                          download_url.c_str())));
2294 }
2295
2296 // Test that cancel()ing an in-progress download causes its state to transition
2297 // to interrupted, and test that that state transition is detectable by an
2298 // onChanged event listener.  TODO(benjhayden): Test other sources of
2299 // interruptions such as server death.
2300 IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
2301                        DownloadExtensionTest_Download_Cancel) {
2302   LoadExtension("downloads_split");
2303   ASSERT_TRUE(StartEmbeddedTestServer());
2304   ASSERT_TRUE(test_server()->Start());
2305   std::string download_url = test_server()->GetURL(
2306       "download-known-size").spec();
2307   GoOnTheRecord();
2308
2309   scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
2310       new DownloadsDownloadFunction(), base::StringPrintf(
2311           "[{\"url\": \"%s\"}]", download_url.c_str())));
2312   ASSERT_TRUE(result.get());
2313   int result_id = -1;
2314   ASSERT_TRUE(result->GetAsInteger(&result_id));
2315   DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
2316   ASSERT_TRUE(item);
2317   ScopedCancellingItem canceller(item);
2318   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
2319
2320   ASSERT_TRUE(WaitFor(downloads::OnCreated::kEventName,
2321                       base::StringPrintf(
2322                           "[{\"danger\": \"safe\","
2323                           "  \"incognito\": false,"
2324                           "  \"mime\": \"application/octet-stream\","
2325                           "  \"paused\": false,"
2326                           "  \"id\": %d,"
2327                           "  \"url\": \"%s\"}]",
2328                           result_id,
2329                           download_url.c_str())));
2330   item->Cancel(true);
2331   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
2332                       base::StringPrintf(
2333                           "[{\"id\": %d,"
2334                           "  \"error\": {\"current\":\"USER_CANCELED\"},"
2335                           "  \"state\": {"
2336                           "    \"previous\": \"in_progress\","
2337                           "    \"current\": \"interrupted\"}}]",
2338                           result_id)));
2339 }
2340
2341 // flaky on mac: crbug.com/392288
2342 #if defined(OS_MACOSX)
2343 #define MAYBE_DownloadExtensionTest_Download_FileSystemURL \
2344         DISABLED_DownloadExtensionTest_Download_FileSystemURL
2345 #else
2346 #define MAYBE_DownloadExtensionTest_Download_FileSystemURL \
2347         DownloadExtensionTest_Download_FileSystemURL
2348 #endif
2349
2350 // Test downloading filesystem: URLs.
2351 // NOTE: chrome disallows creating HTML5 FileSystem Files in incognito.
2352 IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
2353                        MAYBE_DownloadExtensionTest_Download_FileSystemURL) {
2354   static const char kPayloadData[] = "on the record\ndata";
2355   GoOnTheRecord();
2356   LoadExtension("downloads_split");
2357
2358   const std::string download_url = "filesystem:" + GetExtensionURL() +
2359     "temporary/on_record.txt";
2360
2361   // Setup a file in the filesystem which we can download.
2362   ASSERT_TRUE(HTML5FileWriter::CreateFileForTesting(
2363       BrowserContext::GetDefaultStoragePartition(browser()->profile())
2364           ->GetFileSystemContext(),
2365       storage::FileSystemURL::CreateForTest(GURL(download_url)),
2366       kPayloadData,
2367       strlen(kPayloadData)));
2368
2369   // Now download it.
2370   scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
2371       new DownloadsDownloadFunction(), base::StringPrintf(
2372           "[{\"url\": \"%s\"}]", download_url.c_str())));
2373   ASSERT_TRUE(result.get());
2374   int result_id = -1;
2375   ASSERT_TRUE(result->GetAsInteger(&result_id));
2376
2377   DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
2378   ASSERT_TRUE(item);
2379   ScopedCancellingItem canceller(item);
2380   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
2381
2382   ASSERT_TRUE(WaitFor(downloads::OnCreated::kEventName,
2383                       base::StringPrintf(
2384                           "[{\"danger\": \"safe\","
2385                           "  \"incognito\": false,"
2386                           "  \"mime\": \"text/plain\","
2387                           "  \"paused\": false,"
2388                           "  \"url\": \"%s\"}]",
2389                           download_url.c_str())));
2390   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
2391                       base::StringPrintf(
2392                           "[{\"id\": %d,"
2393                           "  \"filename\": {"
2394                           "    \"previous\": \"\","
2395                           "    \"current\": \"%s\"}}]",
2396                           result_id,
2397                           GetFilename("on_record.txt").c_str())));
2398   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
2399                       base::StringPrintf(
2400                           "[{\"id\": %d,"
2401                           "  \"state\": {"
2402                           "    \"previous\": \"in_progress\","
2403                           "    \"current\": \"complete\"}}]",
2404                           result_id)));
2405   std::string disk_data;
2406   EXPECT_TRUE(base::ReadFileToString(item->GetTargetFilePath(), &disk_data));
2407   EXPECT_STREQ(kPayloadData, disk_data.c_str());
2408 }
2409
2410 IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
2411                        DownloadExtensionTest_OnDeterminingFilename_NoChange) {
2412   GoOnTheRecord();
2413   LoadExtension("downloads_split");
2414   AddFilenameDeterminer();
2415   ASSERT_TRUE(StartEmbeddedTestServer());
2416   ASSERT_TRUE(test_server()->Start());
2417   std::string download_url = test_server()->GetURL("slow?0").spec();
2418
2419   // Start downloading a file.
2420   scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
2421       new DownloadsDownloadFunction(), base::StringPrintf(
2422           "[{\"url\": \"%s\"}]", download_url.c_str())));
2423   ASSERT_TRUE(result.get());
2424   int result_id = -1;
2425   ASSERT_TRUE(result->GetAsInteger(&result_id));
2426   DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
2427   ASSERT_TRUE(item);
2428   ScopedCancellingItem canceller(item);
2429   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
2430
2431   // Wait for the onCreated and onDeterminingFilename events.
2432   ASSERT_TRUE(WaitFor(downloads::OnCreated::kEventName,
2433                       base::StringPrintf(
2434                           "[{\"danger\": \"safe\","
2435                           "  \"incognito\": false,"
2436                           "  \"id\": %d,"
2437                           "  \"mime\": \"text/plain\","
2438                           "  \"paused\": false,"
2439                           "  \"url\": \"%s\"}]",
2440                           result_id,
2441                           download_url.c_str())));
2442   ASSERT_TRUE(WaitFor(downloads::OnDeterminingFilename::kEventName,
2443                       base::StringPrintf(
2444                           "[{\"id\": %d,"
2445                           "  \"filename\":\"slow.txt\"}]",
2446                           result_id)));
2447   ASSERT_TRUE(item->GetTargetFilePath().empty());
2448   ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
2449
2450   // Respond to the onDeterminingFilename.
2451   std::string error;
2452   ASSERT_TRUE(ExtensionDownloadsEventRouter::DetermineFilename(
2453       browser()->profile(),
2454       false,
2455       GetExtensionId(),
2456       result_id,
2457       base::FilePath(),
2458       downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY,
2459       &error));
2460   EXPECT_EQ("", error);
2461
2462   // The download should complete successfully.
2463   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
2464                       base::StringPrintf(
2465                           "[{\"id\": %d,"
2466                           "  \"filename\": {"
2467                           "    \"previous\": \"\","
2468                           "    \"current\": \"%s\"}}]",
2469                           result_id,
2470                           GetFilename("slow.txt").c_str())));
2471   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
2472                       base::StringPrintf(
2473                           "[{\"id\": %d,"
2474                           "  \"state\": {"
2475                           "    \"previous\": \"in_progress\","
2476                           "    \"current\": \"complete\"}}]",
2477                           result_id)));
2478 }
2479
2480 // Disabled due to cross-platform flakes; http://crbug.com/370531.
2481 IN_PROC_BROWSER_TEST_F(
2482     DownloadExtensionTest,
2483     DISABLED_DownloadExtensionTest_OnDeterminingFilename_Timeout) {
2484   GoOnTheRecord();
2485   LoadExtension("downloads_split");
2486   AddFilenameDeterminer();
2487   ASSERT_TRUE(StartEmbeddedTestServer());
2488   ASSERT_TRUE(test_server()->Start());
2489   std::string download_url = test_server()->GetURL("slow?0").spec();
2490
2491   ExtensionDownloadsEventRouter::SetDetermineFilenameTimeoutSecondsForTesting(
2492       0);
2493
2494   // Start downloading a file.
2495   scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
2496       new DownloadsDownloadFunction(), base::StringPrintf(
2497           "[{\"url\": \"%s\"}]", download_url.c_str())));
2498   ASSERT_TRUE(result.get());
2499   int result_id = -1;
2500   ASSERT_TRUE(result->GetAsInteger(&result_id));
2501   DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
2502   ASSERT_TRUE(item);
2503   ScopedCancellingItem canceller(item);
2504   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
2505
2506   // Wait for the onCreated and onDeterminingFilename events.
2507   ASSERT_TRUE(WaitFor(downloads::OnCreated::kEventName,
2508       base::StringPrintf("[{\"danger\": \"safe\","
2509                           "  \"incognito\": false,"
2510                           "  \"id\": %d,"
2511                           "  \"mime\": \"text/plain\","
2512                           "  \"paused\": false,"
2513                           "  \"url\": \"%s\"}]",
2514                           result_id,
2515                           download_url.c_str())));
2516   ASSERT_TRUE(WaitFor(
2517       downloads::OnDeterminingFilename::kEventName,
2518       base::StringPrintf("[{\"id\": %d,"
2519                          "  \"filename\":\"slow.txt\"}]",
2520                          result_id)));
2521   ASSERT_TRUE(item->GetTargetFilePath().empty());
2522   ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
2523
2524   // Do not respond to the onDeterminingFilename.
2525
2526   // The download should complete successfully.
2527   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
2528       base::StringPrintf("[{\"id\": %d,"
2529                          "  \"filename\": {"
2530                          "    \"previous\": \"\","
2531                          "    \"current\": \"%s\"}}]",
2532                          result_id,
2533                          GetFilename("slow.txt").c_str())));
2534   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
2535       base::StringPrintf("[{\"id\": %d,"
2536                          "  \"state\": {"
2537                          "    \"previous\": \"in_progress\","
2538                          "    \"current\": \"complete\"}}]",
2539                          result_id)));
2540 }
2541
2542 IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
2543                        DownloadExtensionTest_OnDeterminingFilename_Twice) {
2544   GoOnTheRecord();
2545   LoadExtension("downloads_split");
2546   AddFilenameDeterminer();
2547   ASSERT_TRUE(StartEmbeddedTestServer());
2548   ASSERT_TRUE(test_server()->Start());
2549   std::string download_url = test_server()->GetURL("slow?0").spec();
2550
2551   // Start downloading a file.
2552   scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
2553       new DownloadsDownloadFunction(), base::StringPrintf(
2554           "[{\"url\": \"%s\"}]", download_url.c_str())));
2555   ASSERT_TRUE(result.get());
2556   int result_id = -1;
2557   ASSERT_TRUE(result->GetAsInteger(&result_id));
2558   DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
2559   ASSERT_TRUE(item);
2560   ScopedCancellingItem canceller(item);
2561   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
2562
2563   // Wait for the onCreated and onDeterminingFilename events.
2564   ASSERT_TRUE(WaitFor(downloads::OnCreated::kEventName,
2565       base::StringPrintf("[{\"danger\": \"safe\","
2566                           "  \"incognito\": false,"
2567                           "  \"id\": %d,"
2568                           "  \"mime\": \"text/plain\","
2569                           "  \"paused\": false,"
2570                           "  \"url\": \"%s\"}]",
2571                           result_id,
2572                           download_url.c_str())));
2573   ASSERT_TRUE(WaitFor(
2574       downloads::OnDeterminingFilename::kEventName,
2575       base::StringPrintf("[{\"id\": %d,"
2576                          "  \"filename\":\"slow.txt\"}]",
2577                          result_id)));
2578   ASSERT_TRUE(item->GetTargetFilePath().empty());
2579   ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
2580
2581   // Respond to the onDeterminingFilename.
2582   std::string error;
2583   ASSERT_TRUE(ExtensionDownloadsEventRouter::DetermineFilename(
2584       browser()->profile(),
2585       false,
2586       GetExtensionId(),
2587       result_id,
2588       base::FilePath(),
2589       downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY,
2590       &error));
2591   EXPECT_EQ("", error);
2592
2593   // Calling DetermineFilename again should return an error instead of calling
2594   // DownloadTargetDeterminer.
2595   ASSERT_FALSE(ExtensionDownloadsEventRouter::DetermineFilename(
2596       browser()->profile(),
2597       false,
2598       GetExtensionId(),
2599       result_id,
2600       base::FilePath(FILE_PATH_LITERAL("different")),
2601       downloads::FILENAME_CONFLICT_ACTION_OVERWRITE,
2602       &error));
2603   EXPECT_EQ(errors::kTooManyListeners, error);
2604
2605   // The download should complete successfully.
2606   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
2607       base::StringPrintf("[{\"id\": %d,"
2608                          "  \"filename\": {"
2609                          "    \"previous\": \"\","
2610                          "    \"current\": \"%s\"}}]",
2611                          result_id,
2612                          GetFilename("slow.txt").c_str())));
2613   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
2614       base::StringPrintf("[{\"id\": %d,"
2615                          "  \"state\": {"
2616                          "    \"previous\": \"in_progress\","
2617                          "    \"current\": \"complete\"}}]",
2618                          result_id)));
2619 }
2620
2621 IN_PROC_BROWSER_TEST_F(
2622     DownloadExtensionTest,
2623     DownloadExtensionTest_OnDeterminingFilename_DangerousOverride) {
2624   GoOnTheRecord();
2625   LoadExtension("downloads_split");
2626   AddFilenameDeterminer();
2627   ASSERT_TRUE(StartEmbeddedTestServer());
2628   ASSERT_TRUE(test_server()->Start());
2629   std::string download_url = test_server()->GetURL("slow?0").spec();
2630
2631   // Start downloading a file.
2632   scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
2633       new DownloadsDownloadFunction(), base::StringPrintf(
2634           "[{\"url\": \"%s\"}]", download_url.c_str())));
2635   ASSERT_TRUE(result.get());
2636   int result_id = -1;
2637   ASSERT_TRUE(result->GetAsInteger(&result_id));
2638   DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
2639   ASSERT_TRUE(item);
2640   ScopedCancellingItem canceller(item);
2641   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
2642
2643   ASSERT_TRUE(WaitFor(downloads::OnCreated::kEventName,
2644                       base::StringPrintf(
2645                           "[{\"danger\": \"safe\","
2646                           "  \"incognito\": false,"
2647                           "  \"id\": %d,"
2648                           "  \"mime\": \"text/plain\","
2649                           "  \"paused\": false,"
2650                           "  \"url\": \"%s\"}]",
2651                           result_id,
2652                           download_url.c_str())));
2653   ASSERT_TRUE(WaitFor(downloads::OnDeterminingFilename::kEventName,
2654                       base::StringPrintf(
2655                           "[{\"id\": %d,"
2656                           "  \"filename\":\"slow.txt\"}]",
2657                           result_id)));
2658   ASSERT_TRUE(item->GetTargetFilePath().empty());
2659   ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
2660
2661   // Respond to the onDeterminingFilename.
2662   std::string error;
2663   ASSERT_TRUE(ExtensionDownloadsEventRouter::DetermineFilename(
2664       browser()->profile(),
2665       false,
2666       GetExtensionId(),
2667       result_id,
2668       base::FilePath(FILE_PATH_LITERAL("overridden.swf")),
2669       downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY,
2670       &error));
2671   EXPECT_EQ("", error);
2672
2673   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
2674                       base::StringPrintf(
2675                           "[{\"id\": %d,"
2676                           "  \"danger\": {"
2677                           "    \"previous\":\"safe\","
2678                           "    \"current\":\"file\"}}]",
2679                           result_id)));
2680
2681   item->ValidateDangerousDownload();
2682   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
2683                       base::StringPrintf(
2684                           "[{\"id\": %d,"
2685                           "  \"danger\": {"
2686                           "    \"previous\":\"file\","
2687                           "    \"current\":\"accepted\"}}]",
2688                           result_id)));
2689   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
2690                       base::StringPrintf(
2691                           "[{\"id\": %d,"
2692                           "  \"state\": {"
2693                           "    \"previous\": \"in_progress\","
2694                           "    \"current\": \"complete\"}}]",
2695                           result_id)));
2696   EXPECT_EQ(downloads_directory().AppendASCII("overridden.swf"),
2697             item->GetTargetFilePath());
2698 }
2699
2700 IN_PROC_BROWSER_TEST_F(
2701     DownloadExtensionTest,
2702     DownloadExtensionTest_OnDeterminingFilename_ReferencesParentInvalid) {
2703   GoOnTheRecord();
2704   LoadExtension("downloads_split");
2705   AddFilenameDeterminer();
2706   ASSERT_TRUE(StartEmbeddedTestServer());
2707   ASSERT_TRUE(test_server()->Start());
2708   std::string download_url = test_server()->GetURL("slow?0").spec();
2709
2710   // Start downloading a file.
2711   scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
2712       new DownloadsDownloadFunction(), base::StringPrintf(
2713           "[{\"url\": \"%s\"}]", download_url.c_str())));
2714   ASSERT_TRUE(result.get());
2715   int result_id = -1;
2716   ASSERT_TRUE(result->GetAsInteger(&result_id));
2717   DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
2718   ASSERT_TRUE(item);
2719   ScopedCancellingItem canceller(item);
2720   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
2721
2722   ASSERT_TRUE(WaitFor(downloads::OnCreated::kEventName,
2723                       base::StringPrintf(
2724                           "[{\"danger\": \"safe\","
2725                           "  \"incognito\": false,"
2726                           "  \"id\": %d,"
2727                           "  \"mime\": \"text/plain\","
2728                           "  \"paused\": false,"
2729                           "  \"url\": \"%s\"}]",
2730                           result_id,
2731                           download_url.c_str())));
2732   ASSERT_TRUE(WaitFor(downloads::OnDeterminingFilename::kEventName,
2733                       base::StringPrintf(
2734                           "[{\"id\": %d,"
2735                           "  \"filename\":\"slow.txt\"}]",
2736                           result_id)));
2737   ASSERT_TRUE(item->GetTargetFilePath().empty());
2738   ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
2739
2740   // Respond to the onDeterminingFilename.
2741   std::string error;
2742   ASSERT_FALSE(ExtensionDownloadsEventRouter::DetermineFilename(
2743       browser()->profile(),
2744       false,
2745       GetExtensionId(),
2746       result_id,
2747       base::FilePath(FILE_PATH_LITERAL("sneaky/../../sneaky.txt")),
2748       downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY,
2749       &error));
2750   EXPECT_STREQ(errors::kInvalidFilename, error.c_str());
2751   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
2752                       base::StringPrintf(
2753                           "[{\"id\": %d,"
2754                           "  \"filename\": {"
2755                           "    \"previous\": \"\","
2756                           "    \"current\": \"%s\"}}]",
2757                           result_id,
2758                           GetFilename("slow.txt").c_str())));
2759   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
2760                       base::StringPrintf(
2761                           "[{\"id\": %d,"
2762                           "  \"state\": {"
2763                           "    \"previous\": \"in_progress\","
2764                           "    \"current\": \"complete\"}}]",
2765                           result_id)));
2766 }
2767
2768 IN_PROC_BROWSER_TEST_F(
2769     DownloadExtensionTest,
2770     DownloadExtensionTest_OnDeterminingFilename_IllegalFilename) {
2771   GoOnTheRecord();
2772   LoadExtension("downloads_split");
2773   AddFilenameDeterminer();
2774   ASSERT_TRUE(StartEmbeddedTestServer());
2775   ASSERT_TRUE(test_server()->Start());
2776   std::string download_url = test_server()->GetURL("slow?0").spec();
2777
2778   // Start downloading a file.
2779   scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
2780       new DownloadsDownloadFunction(), base::StringPrintf(
2781           "[{\"url\": \"%s\"}]", download_url.c_str())));
2782   ASSERT_TRUE(result.get());
2783   int result_id = -1;
2784   ASSERT_TRUE(result->GetAsInteger(&result_id));
2785   DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
2786   ASSERT_TRUE(item);
2787   ScopedCancellingItem canceller(item);
2788   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
2789
2790   ASSERT_TRUE(WaitFor(downloads::OnCreated::kEventName,
2791                       base::StringPrintf(
2792                           "[{\"danger\": \"safe\","
2793                           "  \"incognito\": false,"
2794                           "  \"id\": %d,"
2795                           "  \"mime\": \"text/plain\","
2796                           "  \"paused\": false,"
2797                           "  \"url\": \"%s\"}]",
2798                           result_id,
2799                           download_url.c_str())));
2800   ASSERT_TRUE(WaitFor(downloads::OnDeterminingFilename::kEventName,
2801                       base::StringPrintf(
2802                           "[{\"id\": %d,"
2803                           "  \"filename\":\"slow.txt\"}]",
2804                           result_id)));
2805   ASSERT_TRUE(item->GetTargetFilePath().empty());
2806   ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
2807
2808   // Respond to the onDeterminingFilename.
2809   std::string error;
2810   ASSERT_FALSE(ExtensionDownloadsEventRouter::DetermineFilename(
2811       browser()->profile(),
2812       false,
2813       GetExtensionId(),
2814       result_id,
2815       base::FilePath(FILE_PATH_LITERAL("<")),
2816       downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY,
2817       &error));
2818   EXPECT_STREQ(errors::kInvalidFilename, error.c_str());
2819   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
2820                       base::StringPrintf(
2821                           "[{\"id\": %d,"
2822                           "  \"filename\": {"
2823                           "    \"previous\": \"\","
2824                           "    \"current\": \"%s\"}}]",
2825                           result_id,
2826                           GetFilename("slow.txt").c_str())));
2827   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
2828                       base::StringPrintf(
2829                           "[{\"id\": %d,"
2830                           "  \"state\": {"
2831                           "    \"previous\": \"in_progress\","
2832                           "    \"current\": \"complete\"}}]",
2833                           result_id)));
2834 }
2835
2836 IN_PROC_BROWSER_TEST_F(
2837     DownloadExtensionTest,
2838     DownloadExtensionTest_OnDeterminingFilename_IllegalFilenameExtension) {
2839   GoOnTheRecord();
2840   LoadExtension("downloads_split");
2841   AddFilenameDeterminer();
2842   ASSERT_TRUE(StartEmbeddedTestServer());
2843   ASSERT_TRUE(test_server()->Start());
2844   std::string download_url = test_server()->GetURL("slow?0").spec();
2845
2846   // Start downloading a file.
2847   scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
2848       new DownloadsDownloadFunction(), base::StringPrintf(
2849           "[{\"url\": \"%s\"}]", download_url.c_str())));
2850   ASSERT_TRUE(result.get());
2851   int result_id = -1;
2852   ASSERT_TRUE(result->GetAsInteger(&result_id));
2853   DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
2854   ASSERT_TRUE(item);
2855   ScopedCancellingItem canceller(item);
2856   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
2857
2858   ASSERT_TRUE(WaitFor(downloads::OnCreated::kEventName,
2859                       base::StringPrintf(
2860                           "[{\"danger\": \"safe\","
2861                           "  \"incognito\": false,"
2862                           "  \"id\": %d,"
2863                           "  \"mime\": \"text/plain\","
2864                           "  \"paused\": false,"
2865                           "  \"url\": \"%s\"}]",
2866                           result_id,
2867                           download_url.c_str())));
2868   ASSERT_TRUE(WaitFor(downloads::OnDeterminingFilename::kEventName,
2869                       base::StringPrintf(
2870                           "[{\"id\": %d,"
2871                           "  \"filename\":\"slow.txt\"}]",
2872                           result_id)));
2873   ASSERT_TRUE(item->GetTargetFilePath().empty());
2874   ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
2875
2876   // Respond to the onDeterminingFilename.
2877   std::string error;
2878   ASSERT_FALSE(ExtensionDownloadsEventRouter::DetermineFilename(
2879       browser()->profile(),
2880       false,
2881       GetExtensionId(),
2882       result_id,
2883       base::FilePath(FILE_PATH_LITERAL(
2884           "My Computer.{20D04FE0-3AEA-1069-A2D8-08002B30309D}/foo")),
2885       downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY,
2886       &error));
2887   EXPECT_STREQ(errors::kInvalidFilename, error.c_str());
2888   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
2889                       base::StringPrintf(
2890                           "[{\"id\": %d,"
2891                           "  \"filename\": {"
2892                           "    \"previous\": \"\","
2893                           "    \"current\": \"%s\"}}]",
2894                           result_id,
2895                           GetFilename("slow.txt").c_str())));
2896   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
2897                       base::StringPrintf(
2898                           "[{\"id\": %d,"
2899                           "  \"state\": {"
2900                           "    \"previous\": \"in_progress\","
2901                           "    \"current\": \"complete\"}}]",
2902                           result_id)));
2903 }
2904 #if defined(OS_WIN)
2905 #define MAYBE_DownloadExtensionTest_OnDeterminingFilename_ReservedFilename\
2906   DISABLED_DownloadExtensionTest_OnDeterminingFilename_ReservedFilename
2907 #else
2908 #define MAYBE_DownloadExtensionTest_OnDeterminingFilename_ReservedFilename\
2909   DownloadExtensionTest_OnDeterminingFilename_ReservedFilename
2910 #endif
2911 IN_PROC_BROWSER_TEST_F(
2912     DownloadExtensionTest,
2913     MAYBE_DownloadExtensionTest_OnDeterminingFilename_ReservedFilename) {
2914   GoOnTheRecord();
2915   LoadExtension("downloads_split");
2916   AddFilenameDeterminer();
2917   ASSERT_TRUE(StartEmbeddedTestServer());
2918   ASSERT_TRUE(test_server()->Start());
2919   std::string download_url = test_server()->GetURL("slow?0").spec();
2920
2921   // Start downloading a file.
2922   scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
2923       new DownloadsDownloadFunction(), base::StringPrintf(
2924           "[{\"url\": \"%s\"}]", download_url.c_str())));
2925   ASSERT_TRUE(result.get());
2926   int result_id = -1;
2927   ASSERT_TRUE(result->GetAsInteger(&result_id));
2928   DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
2929   ASSERT_TRUE(item);
2930   ScopedCancellingItem canceller(item);
2931   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
2932
2933   ASSERT_TRUE(WaitFor(downloads::OnCreated::kEventName,
2934                       base::StringPrintf(
2935                           "[{\"danger\": \"safe\","
2936                           "  \"incognito\": false,"
2937                           "  \"id\": %d,"
2938                           "  \"mime\": \"text/plain\","
2939                           "  \"paused\": false,"
2940                           "  \"url\": \"%s\"}]",
2941                           result_id,
2942                           download_url.c_str())));
2943   ASSERT_TRUE(WaitFor(downloads::OnDeterminingFilename::kEventName,
2944                       base::StringPrintf(
2945                           "[{\"id\": %d,"
2946                           "  \"filename\":\"slow.txt\"}]",
2947                           result_id)));
2948   ASSERT_TRUE(item->GetTargetFilePath().empty());
2949   ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
2950
2951   // Respond to the onDeterminingFilename.
2952   std::string error;
2953   ASSERT_FALSE(ExtensionDownloadsEventRouter::DetermineFilename(
2954       browser()->profile(),
2955       false,
2956       GetExtensionId(),
2957       result_id,
2958       base::FilePath(FILE_PATH_LITERAL("con.foo")),
2959       downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY,
2960       &error));
2961   EXPECT_STREQ(errors::kInvalidFilename, error.c_str());
2962   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
2963                       base::StringPrintf(
2964                           "[{\"id\": %d,"
2965                           "  \"filename\": {"
2966                           "    \"previous\": \"\","
2967                           "    \"current\": \"%s\"}}]",
2968                           result_id,
2969                           GetFilename("slow.txt").c_str())));
2970   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
2971                       base::StringPrintf(
2972                           "[{\"id\": %d,"
2973                           "  \"state\": {"
2974                           "    \"previous\": \"in_progress\","
2975                           "    \"current\": \"complete\"}}]",
2976                           result_id)));
2977 }
2978
2979 IN_PROC_BROWSER_TEST_F(
2980     DownloadExtensionTest,
2981     DownloadExtensionTest_OnDeterminingFilename_CurDirInvalid) {
2982   GoOnTheRecord();
2983   LoadExtension("downloads_split");
2984   AddFilenameDeterminer();
2985   ASSERT_TRUE(StartEmbeddedTestServer());
2986   ASSERT_TRUE(test_server()->Start());
2987   std::string download_url = test_server()->GetURL("slow?0").spec();
2988
2989   // Start downloading a file.
2990   scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
2991       new DownloadsDownloadFunction(), base::StringPrintf(
2992           "[{\"url\": \"%s\"}]", download_url.c_str())));
2993   ASSERT_TRUE(result.get());
2994   int result_id = -1;
2995   ASSERT_TRUE(result->GetAsInteger(&result_id));
2996   DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
2997   ASSERT_TRUE(item);
2998   ScopedCancellingItem canceller(item);
2999   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
3000
3001   ASSERT_TRUE(WaitFor(downloads::OnCreated::kEventName,
3002                       base::StringPrintf(
3003                           "[{\"danger\": \"safe\","
3004                           "  \"incognito\": false,"
3005                           "  \"id\": %d,"
3006                           "  \"mime\": \"text/plain\","
3007                           "  \"paused\": false,"
3008                           "  \"url\": \"%s\"}]",
3009                           result_id,
3010                           download_url.c_str())));
3011   ASSERT_TRUE(WaitFor(downloads::OnDeterminingFilename::kEventName,
3012                       base::StringPrintf(
3013                           "[{\"id\": %d,"
3014                           "  \"filename\":\"slow.txt\"}]",
3015                           result_id)));
3016   ASSERT_TRUE(item->GetTargetFilePath().empty());
3017   ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
3018
3019   // Respond to the onDeterminingFilename.
3020   std::string error;
3021   ASSERT_FALSE(ExtensionDownloadsEventRouter::DetermineFilename(
3022       browser()->profile(),
3023       false,
3024       GetExtensionId(),
3025       result_id,
3026       base::FilePath(FILE_PATH_LITERAL(".")),
3027       downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY,
3028       &error));
3029   EXPECT_STREQ(errors::kInvalidFilename, error.c_str());
3030   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
3031                       base::StringPrintf(
3032                           "[{\"id\": %d,"
3033                           "  \"filename\": {"
3034                           "    \"previous\": \"\","
3035                           "    \"current\": \"%s\"}}]",
3036                           result_id,
3037                           GetFilename("slow.txt").c_str())));
3038   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
3039                       base::StringPrintf(
3040                           "[{\"id\": %d,"
3041                           "  \"state\": {"
3042                           "    \"previous\": \"in_progress\","
3043                           "    \"current\": \"complete\"}}]",
3044                           result_id)));
3045 }
3046
3047 IN_PROC_BROWSER_TEST_F(
3048     DownloadExtensionTest,
3049     DownloadExtensionTest_OnDeterminingFilename_ParentDirInvalid) {
3050   ASSERT_TRUE(StartEmbeddedTestServer());
3051   ASSERT_TRUE(test_server()->Start());
3052   GoOnTheRecord();
3053   LoadExtension("downloads_split");
3054   AddFilenameDeterminer();
3055   std::string download_url = test_server()->GetURL("slow?0").spec();
3056
3057   // Start downloading a file.
3058   scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
3059       new DownloadsDownloadFunction(), base::StringPrintf(
3060           "[{\"url\": \"%s\"}]", download_url.c_str())));
3061   ASSERT_TRUE(result.get());
3062   int result_id = -1;
3063   ASSERT_TRUE(result->GetAsInteger(&result_id));
3064   DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
3065   ASSERT_TRUE(item);
3066   ScopedCancellingItem canceller(item);
3067   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
3068
3069   ASSERT_TRUE(WaitFor(downloads::OnCreated::kEventName,
3070                       base::StringPrintf(
3071                           "[{\"danger\": \"safe\","
3072                           "  \"incognito\": false,"
3073                           "  \"id\": %d,"
3074                           "  \"mime\": \"text/plain\","
3075                           "  \"paused\": false,"
3076                           "  \"url\": \"%s\"}]",
3077                           result_id,
3078                           download_url.c_str())));
3079   ASSERT_TRUE(WaitFor(downloads::OnDeterminingFilename::kEventName,
3080                       base::StringPrintf(
3081                           "[{\"id\": %d,"
3082                           "  \"filename\":\"slow.txt\"}]",
3083                           result_id)));
3084   ASSERT_TRUE(item->GetTargetFilePath().empty());
3085   ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
3086
3087   // Respond to the onDeterminingFilename.
3088   std::string error;
3089   ASSERT_FALSE(ExtensionDownloadsEventRouter::DetermineFilename(
3090       browser()->profile(),
3091       false,
3092       GetExtensionId(),
3093       result_id,
3094       base::FilePath(FILE_PATH_LITERAL("..")),
3095       downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY,
3096       &error));
3097   EXPECT_STREQ(errors::kInvalidFilename, error.c_str());
3098   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
3099                       base::StringPrintf(
3100                           "[{\"id\": %d,"
3101                           "  \"filename\": {"
3102                           "    \"previous\": \"\","
3103                           "    \"current\": \"%s\"}}]",
3104                           result_id,
3105                           GetFilename("slow.txt").c_str())));
3106   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
3107                       base::StringPrintf(
3108                           "[{\"id\": %d,"
3109                           "  \"state\": {"
3110                           "    \"previous\": \"in_progress\","
3111                           "    \"current\": \"complete\"}}]",
3112                           result_id)));
3113 }
3114
3115 IN_PROC_BROWSER_TEST_F(
3116     DownloadExtensionTest,
3117     DownloadExtensionTest_OnDeterminingFilename_AbsPathInvalid) {
3118   GoOnTheRecord();
3119   LoadExtension("downloads_split");
3120   AddFilenameDeterminer();
3121   ASSERT_TRUE(StartEmbeddedTestServer());
3122   ASSERT_TRUE(test_server()->Start());
3123   std::string download_url = test_server()->GetURL("slow?0").spec();
3124
3125   // Start downloading a file.
3126   scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
3127       new DownloadsDownloadFunction(), base::StringPrintf(
3128           "[{\"url\": \"%s\"}]", download_url.c_str())));
3129   ASSERT_TRUE(result.get());
3130   int result_id = -1;
3131   ASSERT_TRUE(result->GetAsInteger(&result_id));
3132   DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
3133   ASSERT_TRUE(item);
3134   ScopedCancellingItem canceller(item);
3135   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
3136
3137   ASSERT_TRUE(WaitFor(downloads::OnCreated::kEventName,
3138                       base::StringPrintf(
3139                           "[{\"danger\": \"safe\","
3140                           "  \"incognito\": false,"
3141                           "  \"id\": %d,"
3142                           "  \"mime\": \"text/plain\","
3143                           "  \"paused\": false,"
3144                           "  \"url\": \"%s\"}]",
3145                           result_id,
3146                           download_url.c_str())));
3147   ASSERT_TRUE(WaitFor(downloads::OnDeterminingFilename::kEventName,
3148                       base::StringPrintf(
3149                           "[{\"id\": %d,"
3150                           "  \"filename\":\"slow.txt\"}]",
3151                           result_id)));
3152   ASSERT_TRUE(item->GetTargetFilePath().empty());
3153   ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
3154
3155   // Respond to the onDeterminingFilename. Absolute paths should be rejected.
3156   std::string error;
3157   ASSERT_FALSE(ExtensionDownloadsEventRouter::DetermineFilename(
3158       browser()->profile(),
3159       false,
3160       GetExtensionId(),
3161       result_id,
3162       downloads_directory().Append(FILE_PATH_LITERAL("sneaky.txt")),
3163       downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY,
3164       &error));
3165   EXPECT_STREQ(errors::kInvalidFilename, error.c_str());
3166
3167   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
3168                       base::StringPrintf(
3169                           "[{\"id\": %d,"
3170                           "  \"filename\": {"
3171                           "    \"previous\": \"\","
3172                           "    \"current\": \"%s\"}}]",
3173                           result_id,
3174                           GetFilename("slow.txt").c_str())));
3175   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
3176                       base::StringPrintf(
3177                           "[{\"id\": %d,"
3178                           "  \"state\": {"
3179                           "    \"previous\": \"in_progress\","
3180                           "    \"current\": \"complete\"}}]",
3181                           result_id)));
3182 }
3183
3184 IN_PROC_BROWSER_TEST_F(
3185     DownloadExtensionTest,
3186     DownloadExtensionTest_OnDeterminingFilename_EmptyBasenameInvalid) {
3187   GoOnTheRecord();
3188   LoadExtension("downloads_split");
3189   AddFilenameDeterminer();
3190   ASSERT_TRUE(StartEmbeddedTestServer());
3191   ASSERT_TRUE(test_server()->Start());
3192   std::string download_url = test_server()->GetURL("slow?0").spec();
3193
3194   // Start downloading a file.
3195   scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
3196       new DownloadsDownloadFunction(), base::StringPrintf(
3197           "[{\"url\": \"%s\"}]", download_url.c_str())));
3198   ASSERT_TRUE(result.get());
3199   int result_id = -1;
3200   ASSERT_TRUE(result->GetAsInteger(&result_id));
3201   DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
3202   ASSERT_TRUE(item);
3203   ScopedCancellingItem canceller(item);
3204   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
3205
3206   ASSERT_TRUE(WaitFor(downloads::OnCreated::kEventName,
3207                       base::StringPrintf(
3208                           "[{\"danger\": \"safe\","
3209                           "  \"incognito\": false,"
3210                           "  \"id\": %d,"
3211                           "  \"mime\": \"text/plain\","
3212                           "  \"paused\": false,"
3213                           "  \"url\": \"%s\"}]",
3214                           result_id,
3215                           download_url.c_str())));
3216   ASSERT_TRUE(WaitFor(downloads::OnDeterminingFilename::kEventName,
3217                       base::StringPrintf(
3218                           "[{\"id\": %d,"
3219                           "  \"filename\":\"slow.txt\"}]",
3220                           result_id)));
3221   ASSERT_TRUE(item->GetTargetFilePath().empty());
3222   ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
3223
3224   // Respond to the onDeterminingFilename. Empty basenames should be rejected.
3225   std::string error;
3226   ASSERT_FALSE(ExtensionDownloadsEventRouter::DetermineFilename(
3227       browser()->profile(),
3228       false,
3229       GetExtensionId(),
3230       result_id,
3231       base::FilePath(FILE_PATH_LITERAL("foo/")),
3232       downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY,
3233       &error));
3234   EXPECT_STREQ(errors::kInvalidFilename, error.c_str());
3235
3236   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
3237                       base::StringPrintf(
3238                           "[{\"id\": %d,"
3239                           "  \"filename\": {"
3240                           "    \"previous\": \"\","
3241                           "    \"current\": \"%s\"}}]",
3242                           result_id,
3243                           GetFilename("slow.txt").c_str())));
3244   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
3245                       base::StringPrintf(
3246                           "[{\"id\": %d,"
3247                           "  \"state\": {"
3248                           "    \"previous\": \"in_progress\","
3249                           "    \"current\": \"complete\"}}]",
3250                           result_id)));
3251 }
3252
3253 // conflictAction may be specified without filename.
3254 IN_PROC_BROWSER_TEST_F(
3255     DownloadExtensionTest,
3256     DownloadExtensionTest_OnDeterminingFilename_Overwrite) {
3257   GoOnTheRecord();
3258   LoadExtension("downloads_split");
3259   AddFilenameDeterminer();
3260   ASSERT_TRUE(StartEmbeddedTestServer());
3261   ASSERT_TRUE(test_server()->Start());
3262   std::string download_url = test_server()->GetURL("slow?0").spec();
3263
3264   // Start downloading a file.
3265   scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
3266       new DownloadsDownloadFunction(), base::StringPrintf(
3267           "[{\"url\": \"%s\"}]", download_url.c_str())));
3268   ASSERT_TRUE(result.get());
3269   int result_id = -1;
3270   ASSERT_TRUE(result->GetAsInteger(&result_id));
3271   DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
3272   ASSERT_TRUE(item);
3273   ScopedCancellingItem canceller(item);
3274   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
3275   ASSERT_TRUE(WaitFor(downloads::OnCreated::kEventName,
3276                       base::StringPrintf(
3277                           "[{\"danger\": \"safe\","
3278                           "  \"incognito\": false,"
3279                           "  \"id\": %d,"
3280                           "  \"mime\": \"text/plain\","
3281                           "  \"paused\": false,"
3282                           "  \"url\": \"%s\"}]",
3283                           result_id,
3284                           download_url.c_str())));
3285   ASSERT_TRUE(WaitFor(downloads::OnDeterminingFilename::kEventName,
3286                       base::StringPrintf(
3287                           "[{\"id\": %d,"
3288                           "  \"filename\":\"slow.txt\"}]",
3289                           result_id)));
3290   ASSERT_TRUE(item->GetTargetFilePath().empty());
3291   ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
3292
3293   // Respond to the onDeterminingFilename.
3294   std::string error;
3295   ASSERT_TRUE(ExtensionDownloadsEventRouter::DetermineFilename(
3296       browser()->profile(),
3297       false,
3298       GetExtensionId(),
3299       result_id,
3300       base::FilePath(),
3301       downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY,
3302       &error));
3303   EXPECT_EQ("", error);
3304
3305   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
3306                       base::StringPrintf(
3307                           "[{\"id\": %d,"
3308                           "  \"filename\": {"
3309                           "    \"previous\": \"\","
3310                           "    \"current\": \"%s\"}}]",
3311                           result_id,
3312                           GetFilename("slow.txt").c_str())));
3313   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
3314                       base::StringPrintf(
3315                           "[{\"id\": %d,"
3316                           "  \"state\": {"
3317                           "    \"previous\": \"in_progress\","
3318                           "    \"current\": \"complete\"}}]",
3319                           result_id)));
3320
3321   // Start downloading a file.
3322   result.reset(RunFunctionAndReturnResult(
3323       new DownloadsDownloadFunction(), base::StringPrintf(
3324           "[{\"url\": \"%s\"}]", download_url.c_str())));
3325   ASSERT_TRUE(result.get());
3326   result_id = -1;
3327   ASSERT_TRUE(result->GetAsInteger(&result_id));
3328   item = GetCurrentManager()->GetDownload(result_id);
3329   ASSERT_TRUE(item);
3330   ScopedCancellingItem canceller2(item);
3331   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
3332
3333   ASSERT_TRUE(WaitFor(downloads::OnCreated::kEventName,
3334                       base::StringPrintf(
3335                           "[{\"danger\": \"safe\","
3336                           "  \"incognito\": false,"
3337                           "  \"id\": %d,"
3338                           "  \"mime\": \"text/plain\","
3339                           "  \"paused\": false,"
3340                           "  \"url\": \"%s\"}]",
3341                           result_id,
3342                           download_url.c_str())));
3343   ASSERT_TRUE(WaitFor(downloads::OnDeterminingFilename::kEventName,
3344                       base::StringPrintf(
3345                           "[{\"id\": %d,"
3346                           "  \"filename\":\"slow.txt\"}]",
3347                           result_id)));
3348   ASSERT_TRUE(item->GetTargetFilePath().empty());
3349   ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
3350
3351   // Respond to the onDeterminingFilename.
3352   // Also test that DetermineFilename allows (chrome) extensions to set
3353   // filenames without (filename) extensions. (Don't ask about v8 extensions or
3354   // python extensions or kernel extensions or firefox extensions...)
3355   error = "";
3356   ASSERT_TRUE(ExtensionDownloadsEventRouter::DetermineFilename(
3357       browser()->profile(),
3358       false,
3359       GetExtensionId(),
3360       result_id,
3361       base::FilePath(),
3362       downloads::FILENAME_CONFLICT_ACTION_OVERWRITE,
3363       &error));
3364   EXPECT_EQ("", error);
3365
3366   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
3367                       base::StringPrintf(
3368                           "[{\"id\": %d,"
3369                           "  \"filename\": {"
3370                           "    \"previous\": \"\","
3371                           "    \"current\": \"%s\"}}]",
3372                           result_id,
3373                           GetFilename("slow.txt").c_str())));
3374   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
3375                       base::StringPrintf(
3376                           "[{\"id\": %d,"
3377                           "  \"state\": {"
3378                           "    \"previous\": \"in_progress\","
3379                           "    \"current\": \"complete\"}}]",
3380                           result_id)));
3381 }
3382
3383 IN_PROC_BROWSER_TEST_F(
3384     DownloadExtensionTest,
3385     DownloadExtensionTest_OnDeterminingFilename_Override) {
3386   GoOnTheRecord();
3387   LoadExtension("downloads_split");
3388   AddFilenameDeterminer();
3389   ASSERT_TRUE(StartEmbeddedTestServer());
3390   ASSERT_TRUE(test_server()->Start());
3391   std::string download_url = test_server()->GetURL("slow?0").spec();
3392
3393   // Start downloading a file.
3394   scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
3395       new DownloadsDownloadFunction(), base::StringPrintf(
3396           "[{\"url\": \"%s\"}]", download_url.c_str())));
3397   ASSERT_TRUE(result.get());
3398   int result_id = -1;
3399   ASSERT_TRUE(result->GetAsInteger(&result_id));
3400   DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
3401   ASSERT_TRUE(item);
3402   ScopedCancellingItem canceller(item);
3403   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
3404   ASSERT_TRUE(WaitFor(downloads::OnCreated::kEventName,
3405                       base::StringPrintf(
3406                           "[{\"danger\": \"safe\","
3407                           "  \"incognito\": false,"
3408                           "  \"id\": %d,"
3409                           "  \"mime\": \"text/plain\","
3410                           "  \"paused\": false,"
3411                           "  \"url\": \"%s\"}]",
3412                           result_id,
3413                           download_url.c_str())));
3414   ASSERT_TRUE(WaitFor(downloads::OnDeterminingFilename::kEventName,
3415                       base::StringPrintf(
3416                           "[{\"id\": %d,"
3417                           "  \"filename\":\"slow.txt\"}]",
3418                           result_id)));
3419   ASSERT_TRUE(item->GetTargetFilePath().empty());
3420   ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
3421
3422   // Respond to the onDeterminingFilename.
3423   std::string error;
3424   ASSERT_TRUE(ExtensionDownloadsEventRouter::DetermineFilename(
3425       browser()->profile(),
3426       false,
3427       GetExtensionId(),
3428       result_id,
3429       base::FilePath(),
3430       downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY,
3431       &error));
3432   EXPECT_EQ("", error);
3433
3434   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
3435                       base::StringPrintf(
3436                           "[{\"id\": %d,"
3437                           "  \"filename\": {"
3438                           "    \"previous\": \"\","
3439                           "    \"current\": \"%s\"}}]",
3440                           result_id,
3441                           GetFilename("slow.txt").c_str())));
3442   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
3443                       base::StringPrintf(
3444                           "[{\"id\": %d,"
3445                           "  \"state\": {"
3446                           "    \"previous\": \"in_progress\","
3447                           "    \"current\": \"complete\"}}]",
3448                           result_id)));
3449
3450   // Start downloading a file.
3451   result.reset(RunFunctionAndReturnResult(
3452       new DownloadsDownloadFunction(), base::StringPrintf(
3453           "[{\"url\": \"%s\"}]", download_url.c_str())));
3454   ASSERT_TRUE(result.get());
3455   result_id = -1;
3456   ASSERT_TRUE(result->GetAsInteger(&result_id));
3457   item = GetCurrentManager()->GetDownload(result_id);
3458   ASSERT_TRUE(item);
3459   ScopedCancellingItem canceller2(item);
3460   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
3461
3462   ASSERT_TRUE(WaitFor(downloads::OnCreated::kEventName,
3463                       base::StringPrintf(
3464                           "[{\"danger\": \"safe\","
3465                           "  \"incognito\": false,"
3466                           "  \"id\": %d,"
3467                           "  \"mime\": \"text/plain\","
3468                           "  \"paused\": false,"
3469                           "  \"url\": \"%s\"}]",
3470                           result_id,
3471                           download_url.c_str())));
3472   ASSERT_TRUE(WaitFor(downloads::OnDeterminingFilename::kEventName,
3473                       base::StringPrintf(
3474                           "[{\"id\": %d,"
3475                           "  \"filename\":\"slow.txt\"}]",
3476                           result_id)));
3477   ASSERT_TRUE(item->GetTargetFilePath().empty());
3478   ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
3479
3480   // Respond to the onDeterminingFilename.
3481   // Also test that DetermineFilename allows (chrome) extensions to set
3482   // filenames without (filename) extensions. (Don't ask about v8 extensions or
3483   // python extensions or kernel extensions or firefox extensions...)
3484   error = "";
3485   ASSERT_TRUE(ExtensionDownloadsEventRouter::DetermineFilename(
3486       browser()->profile(),
3487       false,
3488       GetExtensionId(),
3489       result_id,
3490       base::FilePath(FILE_PATH_LITERAL("foo")),
3491       downloads::FILENAME_CONFLICT_ACTION_OVERWRITE,
3492       &error));
3493   EXPECT_EQ("", error);
3494
3495   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
3496                       base::StringPrintf(
3497                           "[{\"id\": %d,"
3498                           "  \"filename\": {"
3499                           "    \"previous\": \"\","
3500                           "    \"current\": \"%s\"}}]",
3501                           result_id,
3502                           GetFilename("foo").c_str())));
3503   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
3504                       base::StringPrintf(
3505                           "[{\"id\": %d,"
3506                           "  \"state\": {"
3507                           "    \"previous\": \"in_progress\","
3508                           "    \"current\": \"complete\"}}]",
3509                           result_id)));
3510 }
3511
3512 // TODO test precedence rules: install_time
3513
3514 #if defined(OS_MACOSX)
3515 #define MAYBE_DownloadExtensionTest_OnDeterminingFilename_RemoveFilenameDeterminer \
3516   DISABLED_DownloadExtensionTest_OnDeterminingFilename_RemoveFilenameDeterminer
3517 #else
3518 #define MAYBE_DownloadExtensionTest_OnDeterminingFilename_RemoveFilenameDeterminer \
3519   DownloadExtensionTest_OnDeterminingFilename_RemoveFilenameDeterminer
3520 #endif
3521 IN_PROC_BROWSER_TEST_F(
3522     DownloadExtensionTest,
3523     MAYBE_DownloadExtensionTest_OnDeterminingFilename_RemoveFilenameDeterminer) {
3524   ASSERT_TRUE(StartEmbeddedTestServer());
3525   ASSERT_TRUE(test_server()->Start());
3526   GoOnTheRecord();
3527   LoadExtension("downloads_split");
3528   content::RenderProcessHost* host = AddFilenameDeterminer();
3529   std::string download_url = test_server()->GetURL("slow?0").spec();
3530
3531   // Start downloading a file.
3532   scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
3533       new DownloadsDownloadFunction(), base::StringPrintf(
3534           "[{\"url\": \"%s\"}]", download_url.c_str())));
3535   ASSERT_TRUE(result.get());
3536   int result_id = -1;
3537   ASSERT_TRUE(result->GetAsInteger(&result_id));
3538   DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
3539   ASSERT_TRUE(item);
3540   ScopedCancellingItem canceller(item);
3541   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
3542
3543   ASSERT_TRUE(WaitFor(downloads::OnCreated::kEventName,
3544                       base::StringPrintf(
3545                           "[{\"danger\": \"safe\","
3546                           "  \"incognito\": false,"
3547                           "  \"id\": %d,"
3548                           "  \"mime\": \"text/plain\","
3549                           "  \"paused\": false,"
3550                           "  \"url\": \"%s\"}]",
3551                           result_id,
3552                           download_url.c_str())));
3553   ASSERT_TRUE(WaitFor(downloads::OnDeterminingFilename::kEventName,
3554                       base::StringPrintf(
3555                           "[{\"id\": %d,"
3556                           "  \"filename\":\"slow.txt\"}]",
3557                           result_id)));
3558   ASSERT_TRUE(item->GetTargetFilePath().empty());
3559   ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
3560
3561   // Remove a determiner while waiting for it.
3562   RemoveFilenameDeterminer(host);
3563
3564   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
3565                       base::StringPrintf(
3566                           "[{\"id\": %d,"
3567                           "  \"state\": {"
3568                           "    \"previous\": \"in_progress\","
3569                           "    \"current\": \"complete\"}}]",
3570                           result_id)));
3571 }
3572
3573 IN_PROC_BROWSER_TEST_F(
3574     DownloadExtensionTest,
3575     DownloadExtensionTest_OnDeterminingFilename_IncognitoSplit) {
3576   LoadExtension("downloads_split");
3577   ASSERT_TRUE(StartEmbeddedTestServer());
3578   ASSERT_TRUE(test_server()->Start());
3579   std::string download_url = test_server()->GetURL("slow?0").spec();
3580
3581   GoOnTheRecord();
3582   AddFilenameDeterminer();
3583
3584   GoOffTheRecord();
3585   AddFilenameDeterminer();
3586
3587   // Start an on-record download.
3588   GoOnTheRecord();
3589   scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
3590       new DownloadsDownloadFunction(), base::StringPrintf(
3591           "[{\"url\": \"%s\"}]", download_url.c_str())));
3592   ASSERT_TRUE(result.get());
3593   int result_id = -1;
3594   ASSERT_TRUE(result->GetAsInteger(&result_id));
3595   DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
3596   ASSERT_TRUE(item);
3597   ScopedCancellingItem canceller(item);
3598   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
3599
3600   // Wait for the onCreated and onDeterminingFilename events.
3601   ASSERT_TRUE(WaitFor(downloads::OnCreated::kEventName,
3602                       base::StringPrintf(
3603                           "[{\"danger\": \"safe\","
3604                           "  \"incognito\": false,"
3605                           "  \"id\": %d,"
3606                           "  \"mime\": \"text/plain\","
3607                           "  \"paused\": false,"
3608                           "  \"url\": \"%s\"}]",
3609                           result_id,
3610                           download_url.c_str())));
3611   ASSERT_TRUE(WaitFor(downloads::OnDeterminingFilename::kEventName,
3612                       base::StringPrintf(
3613                           "[{\"id\": %d,"
3614                           "  \"incognito\": false,"
3615                           "  \"filename\":\"slow.txt\"}]",
3616                           result_id)));
3617   ASSERT_TRUE(item->GetTargetFilePath().empty());
3618   ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
3619
3620   // Respond to the onDeterminingFilename events.
3621   std::string error;
3622   ASSERT_TRUE(ExtensionDownloadsEventRouter::DetermineFilename(
3623       current_browser()->profile(),
3624       false,
3625       GetExtensionId(),
3626       result_id,
3627       base::FilePath(FILE_PATH_LITERAL("42.txt")),
3628       downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY,
3629       &error));
3630   EXPECT_EQ("", error);
3631
3632   // The download should complete successfully.
3633   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
3634                       base::StringPrintf(
3635                           "[{\"id\": %d,"
3636                           "  \"filename\": {"
3637                           "    \"previous\": \"\","
3638                           "    \"current\": \"%s\"}}]",
3639                           result_id,
3640                           GetFilename("42.txt").c_str())));
3641   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
3642                       base::StringPrintf(
3643                           "[{\"id\": %d,"
3644                           "  \"state\": {"
3645                           "    \"previous\": \"in_progress\","
3646                           "    \"current\": \"complete\"}}]",
3647                           result_id)));
3648
3649   // Start an incognito download for comparison.
3650   GoOffTheRecord();
3651   result.reset(RunFunctionAndReturnResult(
3652       new DownloadsDownloadFunction(), base::StringPrintf(
3653           "[{\"url\": \"%s\"}]", download_url.c_str())));
3654   ASSERT_TRUE(result.get());
3655   result_id = -1;
3656   ASSERT_TRUE(result->GetAsInteger(&result_id));
3657   item = GetCurrentManager()->GetDownload(result_id);
3658   ASSERT_TRUE(item);
3659   ScopedCancellingItem canceller2(item);
3660   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
3661
3662   ASSERT_TRUE(WaitFor(downloads::OnCreated::kEventName,
3663                       base::StringPrintf(
3664                           "[{\"danger\": \"safe\","
3665                           "  \"incognito\": true,"
3666                           "  \"id\": %d,"
3667                           "  \"mime\": \"text/plain\","
3668                           "  \"paused\": false,"
3669                           "  \"url\": \"%s\"}]",
3670                           result_id,
3671                           download_url.c_str())));
3672   // On-Record renderers should not see events for off-record items.
3673   ASSERT_TRUE(WaitFor(downloads::OnDeterminingFilename::kEventName,
3674                       base::StringPrintf(
3675                           "[{\"id\": %d,"
3676                           "  \"incognito\": true,"
3677                           "  \"filename\":\"slow.txt\"}]",
3678                           result_id)));
3679   ASSERT_TRUE(item->GetTargetFilePath().empty());
3680   ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
3681
3682   // Respond to the onDeterminingFilename.
3683   error = "";
3684   ASSERT_TRUE(ExtensionDownloadsEventRouter::DetermineFilename(
3685       current_browser()->profile(),
3686       false,
3687       GetExtensionId(),
3688       result_id,
3689       base::FilePath(FILE_PATH_LITERAL("5.txt")),
3690       downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY,
3691       &error));
3692   EXPECT_EQ("", error);
3693
3694   // The download should complete successfully.
3695   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
3696                       base::StringPrintf(
3697                           "[{\"id\": %d,"
3698                           "  \"filename\": {"
3699                           "    \"previous\": \"\","
3700                           "    \"current\": \"%s\"}}]",
3701                           result_id,
3702                           GetFilename("5.txt").c_str())));
3703   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
3704                       base::StringPrintf(
3705                           "[{\"id\": %d,"
3706                           "  \"state\": {"
3707                           "    \"previous\": \"in_progress\","
3708                           "    \"current\": \"complete\"}}]",
3709                           result_id)));
3710 }
3711
3712 IN_PROC_BROWSER_TEST_F(
3713     DownloadExtensionTest,
3714     DownloadExtensionTest_OnDeterminingFilename_IncognitoSpanning) {
3715   LoadExtension("downloads_spanning");
3716   ASSERT_TRUE(StartEmbeddedTestServer());
3717   ASSERT_TRUE(test_server()->Start());
3718   std::string download_url = test_server()->GetURL("slow?0").spec();
3719
3720   GoOnTheRecord();
3721   AddFilenameDeterminer();
3722
3723   // There is a single extension renderer that sees both on-record and
3724   // off-record events. The extension functions see the on-record profile with
3725   // include_incognito=true.
3726
3727   // Start an on-record download.
3728   GoOnTheRecord();
3729   scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
3730       new DownloadsDownloadFunction(), base::StringPrintf(
3731           "[{\"url\": \"%s\"}]", download_url.c_str())));
3732   ASSERT_TRUE(result.get());
3733   int result_id = -1;
3734   ASSERT_TRUE(result->GetAsInteger(&result_id));
3735   DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
3736   ASSERT_TRUE(item);
3737   ScopedCancellingItem canceller(item);
3738   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
3739
3740   // Wait for the onCreated and onDeterminingFilename events.
3741   ASSERT_TRUE(WaitFor(downloads::OnCreated::kEventName,
3742                       base::StringPrintf(
3743                           "[{\"danger\": \"safe\","
3744                           "  \"incognito\": false,"
3745                           "  \"id\": %d,"
3746                           "  \"mime\": \"text/plain\","
3747                           "  \"paused\": false,"
3748                           "  \"url\": \"%s\"}]",
3749                           result_id,
3750                           download_url.c_str())));
3751   ASSERT_TRUE(WaitFor(downloads::OnDeterminingFilename::kEventName,
3752                       base::StringPrintf(
3753                           "[{\"id\": %d,"
3754                           "  \"incognito\": false,"
3755                           "  \"filename\":\"slow.txt\"}]",
3756                           result_id)));
3757   ASSERT_TRUE(item->GetTargetFilePath().empty());
3758   ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
3759
3760   // Respond to the onDeterminingFilename events.
3761   std::string error;
3762   ASSERT_TRUE(ExtensionDownloadsEventRouter::DetermineFilename(
3763       current_browser()->profile(),
3764       true,
3765       GetExtensionId(),
3766       result_id,
3767       base::FilePath(FILE_PATH_LITERAL("42.txt")),
3768       downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY,
3769       &error));
3770   EXPECT_EQ("", error);
3771
3772   // The download should complete successfully.
3773   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
3774                       base::StringPrintf(
3775                           "[{\"id\": %d,"
3776                           "  \"filename\": {"
3777                           "    \"previous\": \"\","
3778                           "    \"current\": \"%s\"}}]",
3779                           result_id,
3780                           GetFilename("42.txt").c_str())));
3781   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
3782                       base::StringPrintf(
3783                           "[{\"id\": %d,"
3784                           "  \"state\": {"
3785                           "    \"previous\": \"in_progress\","
3786                           "    \"current\": \"complete\"}}]",
3787                           result_id)));
3788
3789   // Start an incognito download for comparison.
3790   GoOffTheRecord();
3791   result.reset(RunFunctionAndReturnResult(
3792       new DownloadsDownloadFunction(), base::StringPrintf(
3793           "[{\"url\": \"%s\"}]", download_url.c_str())));
3794   ASSERT_TRUE(result.get());
3795   result_id = -1;
3796   ASSERT_TRUE(result->GetAsInteger(&result_id));
3797   item = GetCurrentManager()->GetDownload(result_id);
3798   ASSERT_TRUE(item);
3799   ScopedCancellingItem canceller2(item);
3800   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
3801
3802   ASSERT_TRUE(WaitFor(downloads::OnCreated::kEventName,
3803                       base::StringPrintf(
3804                           "[{\"danger\": \"safe\","
3805                           "  \"incognito\": true,"
3806                           "  \"id\": %d,"
3807                           "  \"mime\": \"text/plain\","
3808                           "  \"paused\": false,"
3809                           "  \"url\": \"%s\"}]",
3810                           result_id,
3811                           download_url.c_str())));
3812   ASSERT_TRUE(WaitFor(downloads::OnDeterminingFilename::kEventName,
3813                       base::StringPrintf(
3814                           "[{\"id\": %d,"
3815                           "  \"incognito\": true,"
3816                           "  \"filename\":\"slow.txt\"}]",
3817                           result_id)));
3818   ASSERT_TRUE(item->GetTargetFilePath().empty());
3819   ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
3820
3821   // Respond to the onDeterminingFilename.
3822   error = "";
3823   ASSERT_TRUE(ExtensionDownloadsEventRouter::DetermineFilename(
3824       current_browser()->profile(),
3825       true,
3826       GetExtensionId(),
3827       result_id,
3828       base::FilePath(FILE_PATH_LITERAL("42.txt")),
3829       downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY,
3830       &error));
3831   EXPECT_EQ("", error);
3832
3833   // The download should complete successfully.
3834   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
3835                       base::StringPrintf(
3836                           "[{\"id\": %d,"
3837                           "  \"filename\": {"
3838                           "    \"previous\": \"\","
3839                           "    \"current\": \"%s\"}}]",
3840                           result_id,
3841                           GetFilename("42 (1).txt").c_str())));
3842   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
3843                       base::StringPrintf(
3844                           "[{\"id\": %d,"
3845                           "  \"state\": {"
3846                           "    \"previous\": \"in_progress\","
3847                           "    \"current\": \"complete\"}}]",
3848                           result_id)));
3849 }
3850
3851 #if defined(OS_WIN)
3852 // This test is very flaky on Win XP and Aura. http://crbug.com/248438
3853 #define MAYBE_DownloadExtensionTest_OnDeterminingFilename_InterruptedResume \
3854     DISABLED_DownloadExtensionTest_OnDeterminingFilename_InterruptedResume
3855 #else
3856 #define MAYBE_DownloadExtensionTest_OnDeterminingFilename_InterruptedResume \
3857     DownloadExtensionTest_OnDeterminingFilename_InterruptedResume
3858 #endif
3859
3860 // Test download interruption while extensions determining filename. Should not
3861 // re-dispatch onDeterminingFilename.
3862 IN_PROC_BROWSER_TEST_F(
3863     DownloadExtensionTest,
3864     MAYBE_DownloadExtensionTest_OnDeterminingFilename_InterruptedResume) {
3865   CommandLine::ForCurrentProcess()->AppendSwitch(
3866       switches::kEnableDownloadResumption);
3867   LoadExtension("downloads_split");
3868   ASSERT_TRUE(StartEmbeddedTestServer());
3869   ASSERT_TRUE(test_server()->Start());
3870   GoOnTheRecord();
3871   content::RenderProcessHost* host = AddFilenameDeterminer();
3872
3873   // Start a download.
3874   DownloadItem* item = NULL;
3875   {
3876     DownloadManager* manager = GetCurrentManager();
3877     scoped_ptr<content::DownloadTestObserver> observer(
3878         new JustInProgressDownloadObserver(manager, 1));
3879     ASSERT_EQ(0, manager->InProgressCount());
3880     ASSERT_EQ(0, manager->NonMaliciousInProgressCount());
3881     // Tabs created just for a download are automatically closed, invalidating
3882     // the download's WebContents. Downloads without WebContents cannot be
3883     // resumed. http://crbug.com/225901
3884     ui_test_utils::NavigateToURLWithDisposition(
3885         current_browser(),
3886         GURL(URLRequestSlowDownloadJob::kUnknownSizeUrl),
3887         CURRENT_TAB,
3888         ui_test_utils::BROWSER_TEST_NONE);
3889     observer->WaitForFinished();
3890     EXPECT_EQ(1u, observer->NumDownloadsSeenInState(DownloadItem::IN_PROGRESS));
3891     DownloadManager::DownloadVector items;
3892     manager->GetAllDownloads(&items);
3893     for (DownloadManager::DownloadVector::iterator iter = items.begin();
3894           iter != items.end(); ++iter) {
3895       if ((*iter)->GetState() == DownloadItem::IN_PROGRESS) {
3896         // There should be only one IN_PROGRESS item.
3897         EXPECT_EQ(NULL, item);
3898         item = *iter;
3899       }
3900     }
3901     ASSERT_TRUE(item);
3902   }
3903   ScopedCancellingItem canceller(item);
3904
3905   // Wait for the onCreated and onDeterminingFilename event.
3906   ASSERT_TRUE(WaitFor(downloads::OnCreated::kEventName,
3907                       base::StringPrintf(
3908                           "[{\"danger\": \"safe\","
3909                           "  \"incognito\": false,"
3910                           "  \"id\": %d,"
3911                           "  \"mime\": \"application/octet-stream\","
3912                           "  \"paused\": false}]",
3913                           item->GetId())));
3914   ASSERT_TRUE(WaitFor(downloads::OnDeterminingFilename::kEventName,
3915                       base::StringPrintf(
3916                           "[{\"id\": %d,"
3917                           "  \"incognito\": false,"
3918                           "  \"filename\":\"download-unknown-size\"}]",
3919                           item->GetId())));
3920   ASSERT_TRUE(item->GetTargetFilePath().empty());
3921   ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
3922
3923   ClearEvents();
3924   ui_test_utils::NavigateToURLWithDisposition(
3925       current_browser(),
3926       GURL(URLRequestSlowDownloadJob::kErrorDownloadUrl),
3927       NEW_BACKGROUND_TAB,
3928       ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
3929
3930   // Errors caught before filename determination are delayed until after
3931   // filename determination.
3932   std::string error;
3933   ASSERT_TRUE(ExtensionDownloadsEventRouter::DetermineFilename(
3934       current_browser()->profile(),
3935       false,
3936       GetExtensionId(),
3937       item->GetId(),
3938       base::FilePath(FILE_PATH_LITERAL("42.txt")),
3939       downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY,
3940       &error))
3941       << error;
3942   EXPECT_EQ("", error);
3943   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
3944                       base::StringPrintf(
3945                           "[{\"id\": %d,"
3946                           "  \"filename\": {"
3947                           "    \"previous\": \"\","
3948                           "    \"current\": \"%s\"}}]",
3949                           item->GetId(),
3950                           GetFilename("42.txt").c_str())));
3951
3952   content::DownloadUpdatedObserver interrupted(item, base::Bind(
3953       ItemIsInterrupted));
3954   ASSERT_TRUE(interrupted.WaitForEvent());
3955   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
3956                       base::StringPrintf(
3957                           "[{\"id\": %d,"
3958                           "  \"error\":{\"current\":\"NETWORK_FAILED\"},"
3959                           "  \"state\":{"
3960                           "    \"previous\":\"in_progress\","
3961                           "    \"current\":\"interrupted\"}}]",
3962                           item->GetId())));
3963
3964   ClearEvents();
3965   // Downloads that are restarted on resumption trigger another download target
3966   // determination.
3967   RemoveFilenameDeterminer(host);
3968   item->Resume();
3969
3970   // Errors caught before filename determination is complete are delayed until
3971   // after filename determination so that, on resumption, filename determination
3972   // does not need to be re-done. So, there will not be a second
3973   // onDeterminingFilename event.
3974
3975   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
3976                       base::StringPrintf(
3977                           "[{\"id\": %d,"
3978                           "  \"error\":{\"previous\":\"NETWORK_FAILED\"},"
3979                           "  \"state\":{"
3980                           "    \"previous\":\"interrupted\","
3981                           "    \"current\":\"in_progress\"}}]",
3982                           item->GetId())));
3983
3984   ClearEvents();
3985   FinishPendingSlowDownloads();
3986
3987   // The download should complete successfully.
3988   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
3989                       base::StringPrintf(
3990                           "[{\"id\": %d,"
3991                           "  \"state\": {"
3992                           "    \"previous\": \"in_progress\","
3993                           "    \"current\": \"complete\"}}]",
3994                           item->GetId())));
3995 }
3996
3997 IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
3998                        DownloadExtensionTest_SetShelfEnabled) {
3999   LoadExtension("downloads_split");
4000   EXPECT_TRUE(RunFunction(new DownloadsSetShelfEnabledFunction(), "[false]"));
4001   EXPECT_FALSE(DownloadServiceFactory::GetForBrowserContext(
4002       browser()->profile())->IsShelfEnabled());
4003   EXPECT_TRUE(RunFunction(new DownloadsSetShelfEnabledFunction(), "[true]"));
4004   EXPECT_TRUE(DownloadServiceFactory::GetForBrowserContext(
4005       browser()->profile())->IsShelfEnabled());
4006   // TODO(benjhayden) Test that existing shelves are hidden.
4007   // TODO(benjhayden) Test multiple extensions.
4008   // TODO(benjhayden) Test disabling extensions.
4009   // TODO(benjhayden) Test that browsers associated with other profiles are not
4010   // affected.
4011   // TODO(benjhayden) Test incognito.
4012 }
4013
4014 // TODO(benjhayden) Figure out why DisableExtension() does not fire
4015 // OnListenerRemoved.
4016
4017 // TODO(benjhayden) Test that the shelf is shown for download() both with and
4018 // without a WebContents.
4019
4020 void OnDangerPromptCreated(DownloadDangerPrompt* prompt) {
4021   prompt->InvokeActionForTesting(DownloadDangerPrompt::ACCEPT);
4022 }
4023
4024 #if defined(OS_MACOSX)
4025 // Flakily triggers and assert on Mac.
4026 // http://crbug.com/180759
4027 #define MAYBE_DownloadExtensionTest_AcceptDanger DISABLED_DownloadExtensionTest_AcceptDanger
4028 #else
4029 #define MAYBE_DownloadExtensionTest_AcceptDanger DownloadExtensionTest_AcceptDanger
4030 #endif
4031 IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
4032                        MAYBE_DownloadExtensionTest_AcceptDanger) {
4033   // Download a file that will be marked dangerous; click the browser action
4034   // button; the browser action poup will call acceptDanger(); when the
4035   // DownloadDangerPrompt is created, pretend that the user clicks the Accept
4036   // button; wait until the download completes.
4037   LoadExtension("downloads_split");
4038   scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
4039       new DownloadsDownloadFunction(),
4040       "[{\"url\": \"data:,\", \"filename\": \"dangerous.swf\"}]"));
4041   ASSERT_TRUE(result.get());
4042   int result_id = -1;
4043   ASSERT_TRUE(result->GetAsInteger(&result_id));
4044   DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
4045   ASSERT_TRUE(item);
4046   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
4047                       base::StringPrintf(
4048                           "[{\"id\": %d, "
4049                           "  \"danger\": {"
4050                           "    \"previous\": \"safe\","
4051                           "    \"current\": \"file\"}}]",
4052                           result_id)));
4053   ASSERT_TRUE(item->IsDangerous());
4054   ScopedCancellingItem canceller(item);
4055   scoped_ptr<content::DownloadTestObserver> observer(
4056       new content::DownloadTestObserverTerminal(
4057           GetCurrentManager(), 1,
4058           content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_IGNORE));
4059   DownloadsAcceptDangerFunction::OnPromptCreatedCallback callback =
4060       base::Bind(&OnDangerPromptCreated);
4061   DownloadsAcceptDangerFunction::OnPromptCreatedForTesting(
4062       &callback);
4063   BrowserActionTestUtil(browser()).Press(0);
4064   observer->WaitForFinished();
4065 }
4066
4067 class DownloadsApiTest : public ExtensionApiTest {
4068  public:
4069   DownloadsApiTest() {}
4070   ~DownloadsApiTest() override {}
4071
4072  private:
4073   DISALLOW_COPY_AND_ASSIGN(DownloadsApiTest);
4074 };
4075
4076
4077 IN_PROC_BROWSER_TEST_F(DownloadsApiTest, DownloadsApiTest) {
4078   ASSERT_TRUE(RunExtensionTest("downloads")) << message_;
4079 }
4080
4081 TEST(DownloadInterruptReasonEnumsSynced,
4082      DownloadInterruptReasonEnumsSynced) {
4083 #define INTERRUPT_REASON(name, value)                                        \
4084   EXPECT_EQ(InterruptReasonContentToExtension(                               \
4085                 content::DOWNLOAD_INTERRUPT_REASON_##name),                  \
4086             downloads::INTERRUPT_REASON_##name);                             \
4087   EXPECT_EQ(                                                                 \
4088       InterruptReasonExtensionToContent(downloads::INTERRUPT_REASON_##name), \
4089       content::DOWNLOAD_INTERRUPT_REASON_##name);
4090 #include "content/public/browser/download_interrupt_reason_values.h"  // NOLINT
4091 #undef INTERRUPT_REASON
4092 }
4093
4094 TEST(ExtensionDetermineDownloadFilenameInternal,
4095      ExtensionDetermineDownloadFilenameInternal) {
4096   std::string winner_id;
4097   base::FilePath filename;
4098   downloads::FilenameConflictAction conflict_action =
4099       downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY;
4100   WarningSet warnings;
4101
4102   // Empty incumbent determiner
4103   warnings.clear();
4104   ExtensionDownloadsEventRouter::DetermineFilenameInternal(
4105       base::FilePath(FILE_PATH_LITERAL("a")),
4106       downloads::FILENAME_CONFLICT_ACTION_OVERWRITE,
4107       "suggester",
4108       base::Time::Now(),
4109       "",
4110       base::Time(),
4111       &winner_id,
4112       &filename,
4113       &conflict_action,
4114       &warnings);
4115   EXPECT_EQ("suggester", winner_id);
4116   EXPECT_EQ(FILE_PATH_LITERAL("a"), filename.value());
4117   EXPECT_EQ(downloads::FILENAME_CONFLICT_ACTION_OVERWRITE, conflict_action);
4118   EXPECT_TRUE(warnings.empty());
4119
4120   // Incumbent wins
4121   warnings.clear();
4122   ExtensionDownloadsEventRouter::DetermineFilenameInternal(
4123       base::FilePath(FILE_PATH_LITERAL("b")),
4124       downloads::FILENAME_CONFLICT_ACTION_PROMPT,
4125       "suggester",
4126       base::Time::Now() - base::TimeDelta::FromDays(1),
4127       "incumbent",
4128       base::Time::Now(),
4129       &winner_id,
4130       &filename,
4131       &conflict_action,
4132       &warnings);
4133   EXPECT_EQ("incumbent", winner_id);
4134   EXPECT_EQ(FILE_PATH_LITERAL("a"), filename.value());
4135   EXPECT_EQ(downloads::FILENAME_CONFLICT_ACTION_OVERWRITE, conflict_action);
4136   EXPECT_FALSE(warnings.empty());
4137   EXPECT_EQ(Warning::kDownloadFilenameConflict,
4138             warnings.begin()->warning_type());
4139   EXPECT_EQ("suggester", warnings.begin()->extension_id());
4140
4141   // Suggester wins
4142   warnings.clear();
4143   ExtensionDownloadsEventRouter::DetermineFilenameInternal(
4144       base::FilePath(FILE_PATH_LITERAL("b")),
4145       downloads::FILENAME_CONFLICT_ACTION_PROMPT,
4146       "suggester",
4147       base::Time::Now(),
4148       "incumbent",
4149       base::Time::Now() - base::TimeDelta::FromDays(1),
4150       &winner_id,
4151       &filename,
4152       &conflict_action,
4153       &warnings);
4154   EXPECT_EQ("suggester", winner_id);
4155   EXPECT_EQ(FILE_PATH_LITERAL("b"), filename.value());
4156   EXPECT_EQ(downloads::FILENAME_CONFLICT_ACTION_PROMPT, conflict_action);
4157   EXPECT_FALSE(warnings.empty());
4158   EXPECT_EQ(Warning::kDownloadFilenameConflict,
4159             warnings.begin()->warning_type());
4160   EXPECT_EQ("incumbent", warnings.begin()->extension_id());
4161 }
4162
4163 }  // namespace extensions
4164
4165 #endif  // http://crbug.com/3061144