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