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