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