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