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.
5 // This file contains download browser tests that are known to be runnable
6 // in a pure content context. Over time tests should be migrated here.
8 #include "base/command_line.h"
9 #include "base/files/file_path.h"
10 #include "base/files/file_util.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/threading/platform_thread.h"
16 #include "base/time/time.h"
17 #include "content/browser/byte_stream.h"
18 #include "content/browser/download/download_file_factory.h"
19 #include "content/browser/download/download_file_impl.h"
20 #include "content/browser/download/download_item_impl.h"
21 #include "content/browser/download/download_manager_impl.h"
22 #include "content/browser/download/download_resource_handler.h"
23 #include "content/browser/web_contents/web_contents_impl.h"
24 #include "content/public/browser/power_save_blocker.h"
25 #include "content/public/common/content_switches.h"
26 #include "content/public/common/webplugininfo.h"
27 #include "content/public/test/browser_test_utils.h"
28 #include "content/public/test/content_browser_test.h"
29 #include "content/public/test/content_browser_test_utils.h"
30 #include "content/public/test/download_test_observer.h"
31 #include "content/public/test/test_file_error_injector.h"
32 #include "content/public/test/test_utils.h"
33 #include "content/shell/browser/shell.h"
34 #include "content/shell/browser/shell_browser_context.h"
35 #include "content/shell/browser/shell_download_manager_delegate.h"
36 #include "content/shell/browser/shell_network_delegate.h"
37 #include "content/test/net/url_request_slow_download_job.h"
38 #include "net/test/embedded_test_server/embedded_test_server.h"
39 #include "net/test/embedded_test_server/http_request.h"
40 #include "net/test/embedded_test_server/http_response.h"
41 #include "net/test/spawned_test_server/spawned_test_server.h"
42 #include "net/test/url_request/url_request_mock_http_job.h"
43 #include "testing/gmock/include/gmock/gmock.h"
44 #include "testing/gtest/include/gtest/gtest.h"
47 #if defined(ENABLE_PLUGINS)
48 #include "content/browser/plugin_service_impl.h"
51 using ::net::test_server::EmbeddedTestServer;
52 using ::testing::AllOf;
53 using ::testing::Field;
54 using ::testing::InSequence;
55 using ::testing::Property;
56 using ::testing::Return;
57 using ::testing::StrictMock;
64 class MockDownloadItemObserver : public DownloadItem::Observer {
66 MockDownloadItemObserver() {}
67 virtual ~MockDownloadItemObserver() {}
69 MOCK_METHOD1(OnDownloadUpdated, void(DownloadItem*));
70 MOCK_METHOD1(OnDownloadOpened, void(DownloadItem*));
71 MOCK_METHOD1(OnDownloadRemoved, void(DownloadItem*));
72 MOCK_METHOD1(OnDownloadDestroyed, void(DownloadItem*));
75 class MockDownloadManagerObserver : public DownloadManager::Observer {
77 MockDownloadManagerObserver(DownloadManager* manager) {
79 manager->AddObserver(this);
81 virtual ~MockDownloadManagerObserver() {
83 manager_->RemoveObserver(this);
86 MOCK_METHOD2(OnDownloadCreated, void(DownloadManager*, DownloadItem*));
87 MOCK_METHOD1(ModelChanged, void(DownloadManager*));
88 void ManagerGoingDown(DownloadManager* manager) {
89 DCHECK_EQ(manager_, manager);
90 MockManagerGoingDown(manager);
92 manager_->RemoveObserver(this);
96 MOCK_METHOD1(MockManagerGoingDown, void(DownloadManager*));
98 DownloadManager* manager_;
101 class DownloadFileWithDelayFactory;
103 static DownloadManagerImpl* DownloadManagerForShell(Shell* shell) {
104 // We're in a content_browsertest; we know that the DownloadManager
105 // is a DownloadManagerImpl.
106 return static_cast<DownloadManagerImpl*>(
107 BrowserContext::GetDownloadManager(
108 shell->web_contents()->GetBrowserContext()));
111 class DownloadFileWithDelay : public DownloadFileImpl {
113 DownloadFileWithDelay(
114 scoped_ptr<DownloadSaveInfo> save_info,
115 const base::FilePath& default_download_directory,
117 const GURL& referrer_url,
119 scoped_ptr<ByteStreamReader> stream,
120 const net::BoundNetLog& bound_net_log,
121 scoped_ptr<PowerSaveBlocker> power_save_blocker,
122 base::WeakPtr<DownloadDestinationObserver> observer,
123 base::WeakPtr<DownloadFileWithDelayFactory> owner);
125 ~DownloadFileWithDelay() override;
127 // Wraps DownloadFileImpl::Rename* and intercepts the return callback,
128 // storing it in the factory that produced this object for later
130 void RenameAndUniquify(const base::FilePath& full_path,
131 const RenameCompletionCallback& callback) override;
132 void RenameAndAnnotate(const base::FilePath& full_path,
133 const RenameCompletionCallback& callback) override;
136 static void RenameCallbackWrapper(
137 const base::WeakPtr<DownloadFileWithDelayFactory>& factory,
138 const RenameCompletionCallback& original_callback,
139 DownloadInterruptReason reason,
140 const base::FilePath& path);
142 // This variable may only be read on the FILE thread, and may only be
143 // indirected through (e.g. methods on DownloadFileWithDelayFactory called)
144 // on the UI thread. This is because after construction,
145 // DownloadFileWithDelay lives on the file thread, but
146 // DownloadFileWithDelayFactory is purely a UI thread object.
147 base::WeakPtr<DownloadFileWithDelayFactory> owner_;
149 DISALLOW_COPY_AND_ASSIGN(DownloadFileWithDelay);
152 // All routines on this class must be called on the UI thread.
153 class DownloadFileWithDelayFactory : public DownloadFileFactory {
155 DownloadFileWithDelayFactory();
156 ~DownloadFileWithDelayFactory() override;
158 // DownloadFileFactory interface.
159 DownloadFile* CreateFile(
160 scoped_ptr<DownloadSaveInfo> save_info,
161 const base::FilePath& default_download_directory,
163 const GURL& referrer_url,
165 scoped_ptr<ByteStreamReader> stream,
166 const net::BoundNetLog& bound_net_log,
167 base::WeakPtr<DownloadDestinationObserver> observer) override;
169 void AddRenameCallback(base::Closure callback);
170 void GetAllRenameCallbacks(std::vector<base::Closure>* results);
172 // Do not return until GetAllRenameCallbacks() will return a non-empty list.
173 void WaitForSomeCallback();
176 base::WeakPtrFactory<DownloadFileWithDelayFactory> weak_ptr_factory_;
177 std::vector<base::Closure> rename_callbacks_;
180 DISALLOW_COPY_AND_ASSIGN(DownloadFileWithDelayFactory);
183 DownloadFileWithDelay::DownloadFileWithDelay(
184 scoped_ptr<DownloadSaveInfo> save_info,
185 const base::FilePath& default_download_directory,
187 const GURL& referrer_url,
189 scoped_ptr<ByteStreamReader> stream,
190 const net::BoundNetLog& bound_net_log,
191 scoped_ptr<PowerSaveBlocker> power_save_blocker,
192 base::WeakPtr<DownloadDestinationObserver> observer,
193 base::WeakPtr<DownloadFileWithDelayFactory> owner)
195 save_info.Pass(), default_download_directory, url, referrer_url,
196 calculate_hash, stream.Pass(), bound_net_log, observer),
199 DownloadFileWithDelay::~DownloadFileWithDelay() {}
201 void DownloadFileWithDelay::RenameAndUniquify(
202 const base::FilePath& full_path,
203 const RenameCompletionCallback& callback) {
204 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
205 DownloadFileImpl::RenameAndUniquify(
206 full_path, base::Bind(DownloadFileWithDelay::RenameCallbackWrapper,
210 void DownloadFileWithDelay::RenameAndAnnotate(
211 const base::FilePath& full_path, const RenameCompletionCallback& callback) {
212 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
213 DownloadFileImpl::RenameAndAnnotate(
214 full_path, base::Bind(DownloadFileWithDelay::RenameCallbackWrapper,
219 void DownloadFileWithDelay::RenameCallbackWrapper(
220 const base::WeakPtr<DownloadFileWithDelayFactory>& factory,
221 const RenameCompletionCallback& original_callback,
222 DownloadInterruptReason reason,
223 const base::FilePath& path) {
224 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
227 factory->AddRenameCallback(base::Bind(original_callback, reason, path));
230 DownloadFileWithDelayFactory::DownloadFileWithDelayFactory()
231 : weak_ptr_factory_(this),
233 DownloadFileWithDelayFactory::~DownloadFileWithDelayFactory() {}
235 DownloadFile* DownloadFileWithDelayFactory::CreateFile(
236 scoped_ptr<DownloadSaveInfo> save_info,
237 const base::FilePath& default_download_directory,
239 const GURL& referrer_url,
241 scoped_ptr<ByteStreamReader> stream,
242 const net::BoundNetLog& bound_net_log,
243 base::WeakPtr<DownloadDestinationObserver> observer) {
244 scoped_ptr<PowerSaveBlocker> psb(
245 PowerSaveBlocker::Create(
246 PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
247 "Download in progress"));
248 return new DownloadFileWithDelay(
249 save_info.Pass(), default_download_directory, url, referrer_url,
250 calculate_hash, stream.Pass(), bound_net_log,
251 psb.Pass(), observer, weak_ptr_factory_.GetWeakPtr());
254 void DownloadFileWithDelayFactory::AddRenameCallback(base::Closure callback) {
255 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
256 rename_callbacks_.push_back(callback);
258 base::MessageLoopForUI::current()->Quit();
261 void DownloadFileWithDelayFactory::GetAllRenameCallbacks(
262 std::vector<base::Closure>* results) {
263 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
264 results->swap(rename_callbacks_);
267 void DownloadFileWithDelayFactory::WaitForSomeCallback() {
268 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
270 if (rename_callbacks_.empty()) {
277 class CountingDownloadFile : public DownloadFileImpl {
279 CountingDownloadFile(
280 scoped_ptr<DownloadSaveInfo> save_info,
281 const base::FilePath& default_downloads_directory,
283 const GURL& referrer_url,
285 scoped_ptr<ByteStreamReader> stream,
286 const net::BoundNetLog& bound_net_log,
287 scoped_ptr<PowerSaveBlocker> power_save_blocker,
288 base::WeakPtr<DownloadDestinationObserver> observer)
289 : DownloadFileImpl(save_info.Pass(), default_downloads_directory,
290 url, referrer_url, calculate_hash,
291 stream.Pass(), bound_net_log, observer) {}
293 ~CountingDownloadFile() override {
294 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
298 void Initialize(const InitializeCallback& callback) override {
299 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
301 return DownloadFileImpl::Initialize(callback);
304 static void GetNumberActiveFiles(int* result) {
305 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
306 *result = active_files_;
309 // Can be called on any thread, and will block (running message loop)
310 // until data is returned.
311 static int GetNumberActiveFilesFromFileThread() {
313 BrowserThread::PostTaskAndReply(
316 base::Bind(&CountingDownloadFile::GetNumberActiveFiles, &result),
317 base::MessageLoop::current()->QuitClosure());
318 base::MessageLoop::current()->Run();
319 DCHECK_NE(-1, result);
324 static int active_files_;
327 int CountingDownloadFile::active_files_ = 0;
329 class CountingDownloadFileFactory : public DownloadFileFactory {
331 CountingDownloadFileFactory() {}
332 ~CountingDownloadFileFactory() override {}
334 // DownloadFileFactory interface.
335 DownloadFile* CreateFile(
336 scoped_ptr<DownloadSaveInfo> save_info,
337 const base::FilePath& default_downloads_directory,
339 const GURL& referrer_url,
341 scoped_ptr<ByteStreamReader> stream,
342 const net::BoundNetLog& bound_net_log,
343 base::WeakPtr<DownloadDestinationObserver> observer) override {
344 scoped_ptr<PowerSaveBlocker> psb(
345 PowerSaveBlocker::Create(
346 PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
347 "Download in progress"));
348 return new CountingDownloadFile(
349 save_info.Pass(), default_downloads_directory, url, referrer_url,
350 calculate_hash, stream.Pass(), bound_net_log,
351 psb.Pass(), observer);
355 class TestShellDownloadManagerDelegate : public ShellDownloadManagerDelegate {
357 TestShellDownloadManagerDelegate()
358 : delay_download_open_(false) {}
359 ~TestShellDownloadManagerDelegate() override {}
361 bool ShouldOpenDownload(
363 const DownloadOpenDelayedCallback& callback) override {
364 if (delay_download_open_) {
365 delayed_callbacks_.push_back(callback);
371 void SetDelayedOpen(bool delay) {
372 delay_download_open_ = delay;
375 void GetDelayedCallbacks(
376 std::vector<DownloadOpenDelayedCallback>* callbacks) {
377 callbacks->swap(delayed_callbacks_);
380 bool delay_download_open_;
381 std::vector<DownloadOpenDelayedCallback> delayed_callbacks_;
384 // Record all state transitions and byte counts on the observed download.
385 class RecordingDownloadObserver : DownloadItem::Observer {
387 struct RecordStruct {
388 DownloadItem::DownloadState state;
392 typedef std::vector<RecordStruct> RecordVector;
394 RecordingDownloadObserver(DownloadItem* download)
395 : download_(download) {
396 last_state_.state = download->GetState();
397 last_state_.bytes_received = download->GetReceivedBytes();
398 download_->AddObserver(this);
401 ~RecordingDownloadObserver() override { RemoveObserver(); }
403 void CompareToExpectedRecord(const RecordStruct expected[], size_t size) {
404 EXPECT_EQ(size, record_.size());
405 int min = size > record_.size() ? record_.size() : size;
406 for (int i = 0; i < min; ++i) {
407 EXPECT_EQ(expected[i].state, record_[i].state) << "Iteration " << i;
408 EXPECT_EQ(expected[i].bytes_received, record_[i].bytes_received)
409 << "Iteration " << i;
414 void OnDownloadUpdated(DownloadItem* download) override {
415 DCHECK_EQ(download_, download);
416 DownloadItem::DownloadState state = download->GetState();
417 int bytes = download->GetReceivedBytes();
418 if (last_state_.state != state || last_state_.bytes_received > bytes) {
419 last_state_.state = state;
420 last_state_.bytes_received = bytes;
421 record_.push_back(last_state_);
425 void OnDownloadDestroyed(DownloadItem* download) override {
426 DCHECK_EQ(download_, download);
430 void RemoveObserver() {
432 download_->RemoveObserver(this);
437 DownloadItem* download_;
438 RecordStruct last_state_;
439 RecordVector record_;
442 // Get the next created download.
443 class DownloadCreateObserver : DownloadManager::Observer {
445 DownloadCreateObserver(DownloadManager* manager)
449 manager_->AddObserver(this);
452 ~DownloadCreateObserver() override {
454 manager_->RemoveObserver(this);
458 void ManagerGoingDown(DownloadManager* manager) override {
459 DCHECK_EQ(manager_, manager);
460 manager_->RemoveObserver(this);
464 void OnDownloadCreated(DownloadManager* manager,
465 DownloadItem* download) override {
470 base::MessageLoopForUI::current()->Quit();
473 DownloadItem* WaitForFinished() {
474 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
484 DownloadManager* manager_;
490 // Filter for waiting for a certain number of bytes.
491 bool DataReceivedFilter(int number_of_bytes, DownloadItem* download) {
492 return download->GetReceivedBytes() >= number_of_bytes;
495 // Filter for download completion.
496 bool DownloadCompleteFilter(DownloadItem* download) {
497 return download->GetState() == DownloadItem::COMPLETE;
500 // Filter for saving the size of the download when the first IN_PROGRESS
502 bool InitialSizeFilter(int* download_size, DownloadItem* download) {
503 if (download->GetState() != DownloadItem::IN_PROGRESS)
506 *download_size = download->GetReceivedBytes();
510 // Request handler to be used with CreateRedirectHandler().
511 scoped_ptr<net::test_server::HttpResponse> HandleRequestAndSendRedirectResponse(
512 const std::string& relative_url,
513 const GURL& target_url,
514 const net::test_server::HttpRequest& request) {
515 scoped_ptr<net::test_server::BasicHttpResponse> response;
516 if (request.relative_url == relative_url) {
517 response.reset(new net::test_server::BasicHttpResponse);
518 response->set_code(net::HTTP_FOUND);
519 response->AddCustomHeader("Location", target_url.spec());
521 return response.Pass();
524 // Creates a request handler for EmbeddedTestServer that responds with a HTTP
525 // 302 redirect if the request URL matches |relative_url|.
526 EmbeddedTestServer::HandleRequestCallback CreateRedirectHandler(
527 const std::string& relative_url,
528 const GURL& target_url) {
530 &HandleRequestAndSendRedirectResponse, relative_url, target_url);
533 // Request handler to be used with CreateBasicResponseHandler().
534 scoped_ptr<net::test_server::HttpResponse> HandleRequestAndSendBasicResponse(
535 const std::string& relative_url,
536 const std::string& content_type,
537 const std::string& body,
538 const net::test_server::HttpRequest& request) {
539 scoped_ptr<net::test_server::BasicHttpResponse> response;
540 if (request.relative_url == relative_url) {
541 response.reset(new net::test_server::BasicHttpResponse);
542 response->set_content_type(content_type);
543 response->set_content(body);
545 return response.Pass();
548 // Creates a request handler for an EmbeddedTestServer that response with an
549 // HTTP 200 status code, a Content-Type header and a body.
550 EmbeddedTestServer::HandleRequestCallback CreateBasicResponseHandler(
551 const std::string& relative_url,
552 const std::string& content_type,
553 const std::string& body) {
555 &HandleRequestAndSendBasicResponse, relative_url, content_type, body);
560 class DownloadContentTest : public ContentBrowserTest {
562 // An initial send from a website of at least this size will not be
563 // help up by buffering in the underlying downloads ByteStream data
564 // transfer. This is important because on resumption tests we wait
565 // until we've gotten the data we expect before allowing the test server
566 // to send its reset, to get around hard close semantics on the Windows
567 // socket layer implementation.
568 int GetSafeBufferChunk() const {
569 return (DownloadResourceHandler::kDownloadByteStreamSize /
570 ByteStreamWriter::kFractionBufferBeforeSending) + 1;
573 void SetUpOnMainThread() override {
574 ASSERT_TRUE(downloads_directory_.CreateUniqueTempDir());
576 test_delegate_.reset(new TestShellDownloadManagerDelegate());
577 test_delegate_->SetDownloadBehaviorForTesting(downloads_directory_.path());
578 DownloadManager* manager = DownloadManagerForShell(shell());
579 manager->GetDelegate()->Shutdown();
580 manager->SetDelegate(test_delegate_.get());
581 test_delegate_->SetDownloadManager(manager);
583 BrowserThread::PostTask(
584 BrowserThread::IO, FROM_HERE,
585 base::Bind(&URLRequestSlowDownloadJob::AddUrlHandler));
586 base::FilePath mock_base(GetTestFilePath("download", ""));
587 BrowserThread::PostTask(
591 &net::URLRequestMockHTTPJob::AddUrlHandler,
593 make_scoped_refptr(content::BrowserThread::GetBlockingPool())));
596 TestShellDownloadManagerDelegate* GetDownloadManagerDelegate() {
597 return test_delegate_.get();
600 // Create a DownloadTestObserverTerminal that will wait for the
601 // specified number of downloads to finish.
602 DownloadTestObserver* CreateWaiter(
603 Shell* shell, int num_downloads) {
604 DownloadManager* download_manager = DownloadManagerForShell(shell);
605 return new DownloadTestObserverTerminal(download_manager, num_downloads,
606 DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL);
609 // Create a DownloadTestObserverInProgress that will wait for the
610 // specified number of downloads to start.
611 DownloadCreateObserver* CreateInProgressWaiter(
612 Shell* shell, int num_downloads) {
613 DownloadManager* download_manager = DownloadManagerForShell(shell);
614 return new DownloadCreateObserver(download_manager);
617 DownloadTestObserver* CreateInterruptedWaiter(
618 Shell* shell, int num_downloads) {
619 DownloadManager* download_manager = DownloadManagerForShell(shell);
620 return new DownloadTestObserverInterrupted(download_manager, num_downloads,
621 DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL);
624 // Note: Cannot be used with other alternative DownloadFileFactorys
625 void SetupEnsureNoPendingDownloads() {
626 DownloadManagerForShell(shell())->SetDownloadFileFactoryForTesting(
627 scoped_ptr<DownloadFileFactory>(
628 new CountingDownloadFileFactory()).Pass());
631 bool EnsureNoPendingDownloads() {
633 BrowserThread::PostTask(
634 BrowserThread::IO, FROM_HERE,
635 base::Bind(&EnsureNoPendingDownloadJobsOnIO, &result));
636 base::MessageLoop::current()->Run();
638 (CountingDownloadFile::GetNumberActiveFilesFromFileThread() == 0);
641 void NavigateToURLAndWaitForDownload(
644 DownloadItem::DownloadState expected_terminal_state) {
645 scoped_ptr<DownloadTestObserver> observer(CreateWaiter(shell, 1));
646 NavigateToURL(shell, url);
647 observer->WaitForFinished();
648 EXPECT_EQ(1u, observer->NumDownloadsSeenInState(expected_terminal_state));
651 // Checks that |path| is has |file_size| bytes, and matches the |value|
653 bool VerifyFile(const base::FilePath& path,
654 const std::string& value,
655 const int64 file_size) {
656 std::string file_contents;
658 bool read = base::ReadFileToString(path, &file_contents);
659 EXPECT_TRUE(read) << "Failed reading file: " << path.value() << std::endl;
661 return false; // Couldn't read the file.
663 // Note: we don't handle really large files (more than size_t can hold)
664 // so we will fail in that case.
665 size_t expected_size = static_cast<size_t>(file_size);
668 EXPECT_EQ(expected_size, file_contents.size());
669 if (expected_size != file_contents.size())
672 // Check the contents.
673 EXPECT_EQ(value, file_contents);
674 if (memcmp(file_contents.c_str(), value.c_str(), expected_size) != 0)
680 // Start a download and return the item.
681 DownloadItem* StartDownloadAndReturnItem(GURL url) {
682 scoped_ptr<DownloadCreateObserver> observer(
683 CreateInProgressWaiter(shell(), 1));
684 NavigateToURL(shell(), url);
685 observer->WaitForFinished();
686 std::vector<DownloadItem*> downloads;
687 DownloadManagerForShell(shell())->GetAllDownloads(&downloads);
688 EXPECT_EQ(1u, downloads.size());
689 if (1u != downloads.size())
695 void WaitForData(DownloadItem* download, int size) {
696 DownloadUpdatedObserver data_observer(
697 download, base::Bind(&DataReceivedFilter, size));
698 data_observer.WaitForEvent();
699 ASSERT_EQ(size, download->GetReceivedBytes());
700 ASSERT_EQ(DownloadItem::IN_PROGRESS, download->GetState());
703 // Tell the test server to release a pending RST and confirm
704 // that the interrupt is received properly (for download resumption
706 void ReleaseRSTAndConfirmInterruptForResume(DownloadItem* download) {
707 scoped_ptr<DownloadTestObserver> rst_observer(
708 CreateInterruptedWaiter(shell(), 1));
709 NavigateToURL(shell(), test_server()->GetURL("download-finish"));
710 rst_observer->WaitForFinished();
711 EXPECT_EQ(DownloadItem::INTERRUPTED, download->GetState());
714 // Confirm file status expected for the given location in a stream
715 // provided by the resume test server.
716 void ConfirmFileStatusForResume(
717 DownloadItem* download, bool file_exists,
718 int received_bytes, int total_bytes,
719 const base::FilePath& expected_filename) {
720 // expected_filename is only known if the file exists.
721 ASSERT_EQ(file_exists, !expected_filename.empty());
722 EXPECT_EQ(received_bytes, download->GetReceivedBytes());
723 EXPECT_EQ(total_bytes, download->GetTotalBytes());
724 EXPECT_EQ(expected_filename.value(),
725 download->GetFullPath().BaseName().value());
726 EXPECT_EQ(file_exists,
727 (!download->GetFullPath().empty() &&
728 base::PathExists(download->GetFullPath())));
731 std::string file_contents;
732 EXPECT_TRUE(base::ReadFileToString(
733 download->GetFullPath(), &file_contents));
735 ASSERT_EQ(static_cast<size_t>(received_bytes), file_contents.size());
736 for (int i = 0; i < received_bytes; ++i) {
737 EXPECT_EQ(static_cast<char>((i * 2 + 15) % 256), file_contents[i])
738 << "File contents diverged at position " << i
739 << " for " << expected_filename.value();
741 if (static_cast<char>((i * 2 + 15) % 256) != file_contents[i])
748 static void EnsureNoPendingDownloadJobsOnIO(bool* result) {
749 if (URLRequestSlowDownloadJob::NumberOutstandingRequests())
751 BrowserThread::PostTask(
752 BrowserThread::UI, FROM_HERE, base::MessageLoop::QuitClosure());
755 // Location of the downloads directory for these tests
756 base::ScopedTempDir downloads_directory_;
757 scoped_ptr<TestShellDownloadManagerDelegate> test_delegate_;
760 IN_PROC_BROWSER_TEST_F(DownloadContentTest, DownloadCancelled) {
761 SetupEnsureNoPendingDownloads();
763 // Create a download, wait until it's started, and confirm
764 // we're in the expected state.
765 scoped_ptr<DownloadCreateObserver> observer(
766 CreateInProgressWaiter(shell(), 1));
767 NavigateToURL(shell(), GURL(URLRequestSlowDownloadJob::kUnknownSizeUrl));
768 observer->WaitForFinished();
770 std::vector<DownloadItem*> downloads;
771 DownloadManagerForShell(shell())->GetAllDownloads(&downloads);
772 ASSERT_EQ(1u, downloads.size());
773 ASSERT_EQ(DownloadItem::IN_PROGRESS, downloads[0]->GetState());
775 // Cancel the download and wait for download system quiesce.
776 downloads[0]->Cancel(true);
777 scoped_refptr<DownloadTestFlushObserver> flush_observer(
778 new DownloadTestFlushObserver(DownloadManagerForShell(shell())));
779 flush_observer->WaitForFlush();
781 // Get the important info from other threads and check it.
782 EXPECT_TRUE(EnsureNoPendingDownloads());
785 // Check that downloading multiple (in this case, 2) files does not result in
787 IN_PROC_BROWSER_TEST_F(DownloadContentTest, MultiDownload) {
788 SetupEnsureNoPendingDownloads();
790 // Create a download, wait until it's started, and confirm
791 // we're in the expected state.
792 scoped_ptr<DownloadCreateObserver> observer1(
793 CreateInProgressWaiter(shell(), 1));
794 NavigateToURL(shell(), GURL(URLRequestSlowDownloadJob::kUnknownSizeUrl));
795 observer1->WaitForFinished();
797 std::vector<DownloadItem*> downloads;
798 DownloadManagerForShell(shell())->GetAllDownloads(&downloads);
799 ASSERT_EQ(1u, downloads.size());
800 ASSERT_EQ(DownloadItem::IN_PROGRESS, downloads[0]->GetState());
801 DownloadItem* download1 = downloads[0]; // The only download.
803 // Start the second download and wait until it's done.
804 base::FilePath file(FILE_PATH_LITERAL("download-test.lib"));
805 GURL url(net::URLRequestMockHTTPJob::GetMockUrl(file));
806 // Download the file and wait.
807 NavigateToURLAndWaitForDownload(shell(), url, DownloadItem::COMPLETE);
809 // Should now have 2 items on the manager.
811 DownloadManagerForShell(shell())->GetAllDownloads(&downloads);
812 ASSERT_EQ(2u, downloads.size());
813 // We don't know the order of the downloads.
814 DownloadItem* download2 = downloads[(download1 == downloads[0]) ? 1 : 0];
816 ASSERT_EQ(DownloadItem::IN_PROGRESS, download1->GetState());
817 ASSERT_EQ(DownloadItem::COMPLETE, download2->GetState());
819 // Allow the first request to finish.
820 scoped_ptr<DownloadTestObserver> observer2(CreateWaiter(shell(), 1));
821 NavigateToURL(shell(), GURL(URLRequestSlowDownloadJob::kFinishDownloadUrl));
822 observer2->WaitForFinished(); // Wait for the third request.
823 EXPECT_EQ(1u, observer2->NumDownloadsSeenInState(DownloadItem::COMPLETE));
825 // Get the important info from other threads and check it.
826 EXPECT_TRUE(EnsureNoPendingDownloads());
828 // The |DownloadItem|s should now be done and have the final file names.
829 // Verify that the files have the expected data and size.
830 // |file1| should be full of '*'s, and |file2| should be the same as the
832 base::FilePath file1(download1->GetTargetFilePath());
833 size_t file_size1 = URLRequestSlowDownloadJob::kFirstDownloadSize +
834 URLRequestSlowDownloadJob::kSecondDownloadSize;
835 std::string expected_contents(file_size1, '*');
836 ASSERT_TRUE(VerifyFile(file1, expected_contents, file_size1));
838 base::FilePath file2(download2->GetTargetFilePath());
839 ASSERT_TRUE(base::ContentsEqual(
840 file2, GetTestFilePath("download", "download-test.lib")));
843 #if defined(ENABLE_PLUGINS)
844 // Content served with a MIME type of application/octet-stream should be
845 // downloaded even when a plugin can be found that handles the file type.
846 IN_PROC_BROWSER_TEST_F(DownloadContentTest, DownloadOctetStream) {
847 const base::FilePath::CharType kTestFilePath[] =
848 FILE_PATH_LITERAL("octet-stream.abc");
849 const char kTestPluginName[] = "TestPlugin";
850 const char kTestMimeType[] = "application/x-test-mime-type";
851 const char kTestFileType[] = "abc";
853 WebPluginInfo plugin_info;
854 plugin_info.name = base::ASCIIToUTF16(kTestPluginName);
855 plugin_info.mime_types.push_back(
856 WebPluginMimeType(kTestMimeType, kTestFileType, ""));
857 PluginServiceImpl::GetInstance()->RegisterInternalPlugin(plugin_info, false);
859 // The following is served with a Content-Type of application/octet-stream.
861 net::URLRequestMockHTTPJob::GetMockUrl(base::FilePath(kTestFilePath)));
862 NavigateToURLAndWaitForDownload(shell(), url, DownloadItem::COMPLETE);
866 // Try to cancel just before we release the download file, by delaying final
868 IN_PROC_BROWSER_TEST_F(DownloadContentTest, CancelAtFinalRename) {
869 // Setup new factory.
870 DownloadFileWithDelayFactory* file_factory =
871 new DownloadFileWithDelayFactory();
872 DownloadManagerImpl* download_manager(DownloadManagerForShell(shell()));
873 download_manager->SetDownloadFileFactoryForTesting(
874 scoped_ptr<DownloadFileFactory>(file_factory).Pass());
877 base::FilePath file(FILE_PATH_LITERAL("download-test.lib"));
878 NavigateToURL(shell(), net::URLRequestMockHTTPJob::GetMockUrl(file));
880 // Wait until the first (intermediate file) rename and execute the callback.
881 file_factory->WaitForSomeCallback();
882 std::vector<base::Closure> callbacks;
883 file_factory->GetAllRenameCallbacks(&callbacks);
884 ASSERT_EQ(1u, callbacks.size());
888 // Wait until the second (final) rename callback is posted.
889 file_factory->WaitForSomeCallback();
890 file_factory->GetAllRenameCallbacks(&callbacks);
891 ASSERT_EQ(1u, callbacks.size());
894 std::vector<DownloadItem*> items;
895 download_manager->GetAllDownloads(&items);
896 ASSERT_EQ(1u, items.size());
897 items[0]->Cancel(true);
898 RunAllPendingInMessageLoop();
901 EXPECT_EQ(DownloadItem::CANCELLED, items[0]->GetState());
903 // Run final rename callback.
908 EXPECT_EQ(DownloadItem::CANCELLED, items[0]->GetState());
911 // Try to cancel just after we release the download file, by delaying
912 // in ShouldOpenDownload.
913 IN_PROC_BROWSER_TEST_F(DownloadContentTest, CancelAtRelease) {
914 DownloadManagerImpl* download_manager(DownloadManagerForShell(shell()));
916 // Mark delegate for delayed open.
917 GetDownloadManagerDelegate()->SetDelayedOpen(true);
919 // Setup new factory.
920 DownloadFileWithDelayFactory* file_factory =
921 new DownloadFileWithDelayFactory();
922 download_manager->SetDownloadFileFactoryForTesting(
923 scoped_ptr<DownloadFileFactory>(file_factory).Pass());
926 base::FilePath file(FILE_PATH_LITERAL("download-test.lib"));
927 NavigateToURL(shell(), net::URLRequestMockHTTPJob::GetMockUrl(file));
929 // Wait until the first (intermediate file) rename and execute the callback.
930 file_factory->WaitForSomeCallback();
931 std::vector<base::Closure> callbacks;
932 file_factory->GetAllRenameCallbacks(&callbacks);
933 ASSERT_EQ(1u, callbacks.size());
937 // Wait until the second (final) rename callback is posted.
938 file_factory->WaitForSomeCallback();
939 file_factory->GetAllRenameCallbacks(&callbacks);
940 ASSERT_EQ(1u, callbacks.size());
946 // Confirm download still IN_PROGRESS (internal state COMPLETING).
947 std::vector<DownloadItem*> items;
948 download_manager->GetAllDownloads(&items);
949 EXPECT_EQ(DownloadItem::IN_PROGRESS, items[0]->GetState());
951 // Cancel the download; confirm cancel fails.
952 ASSERT_EQ(1u, items.size());
953 items[0]->Cancel(true);
954 EXPECT_EQ(DownloadItem::IN_PROGRESS, items[0]->GetState());
956 // Need to complete open test.
957 std::vector<DownloadOpenDelayedCallback> delayed_callbacks;
958 GetDownloadManagerDelegate()->GetDelayedCallbacks(
960 ASSERT_EQ(1u, delayed_callbacks.size());
961 delayed_callbacks[0].Run(true);
963 // *Now* the download should be complete.
964 EXPECT_EQ(DownloadItem::COMPLETE, items[0]->GetState());
967 // Try to shutdown with a download in progress to make sure shutdown path
969 IN_PROC_BROWSER_TEST_F(DownloadContentTest, ShutdownInProgress) {
970 // Create a download that won't complete.
971 scoped_ptr<DownloadCreateObserver> observer(
972 CreateInProgressWaiter(shell(), 1));
973 NavigateToURL(shell(), GURL(URLRequestSlowDownloadJob::kUnknownSizeUrl));
974 observer->WaitForFinished();
977 std::vector<DownloadItem*> items;
978 DownloadManagerForShell(shell())->GetAllDownloads(&items);
979 ASSERT_EQ(1u, items.size());
980 EXPECT_EQ(DownloadItem::IN_PROGRESS, items[0]->GetState());
982 // Shutdown the download manager and make sure we get the right
983 // notifications in the right order.
984 StrictMock<MockDownloadItemObserver> item_observer;
985 items[0]->AddObserver(&item_observer);
986 MockDownloadManagerObserver manager_observer(
987 DownloadManagerForShell(shell()));
988 // Don't care about ModelChanged() events.
989 EXPECT_CALL(manager_observer, ModelChanged(_))
990 .WillRepeatedly(Return());
992 InSequence notifications;
994 EXPECT_CALL(manager_observer, MockManagerGoingDown(
995 DownloadManagerForShell(shell())))
997 EXPECT_CALL(item_observer, OnDownloadUpdated(
999 Property(&DownloadItem::GetState, DownloadItem::CANCELLED))))
1000 .WillOnce(Return());
1001 EXPECT_CALL(item_observer, OnDownloadDestroyed(items[0]))
1002 .WillOnce(Return());
1005 // See http://crbug.com/324525. If we have a refcount release/post task
1006 // race, the second post will stall the IO thread long enough so that we'll
1007 // lose the race and crash. The first stall is just to give the UI thread
1008 // a chance to get the second stall onto the IO thread queue after the cancel
1009 // message created by Shutdown and before the notification callback
1010 // created by the IO thread in canceling the request.
1011 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
1012 base::Bind(&base::PlatformThread::Sleep,
1013 base::TimeDelta::FromMilliseconds(25)));
1014 DownloadManagerForShell(shell())->Shutdown();
1015 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
1016 base::Bind(&base::PlatformThread::Sleep,
1017 base::TimeDelta::FromMilliseconds(25)));
1021 // Try to shutdown just after we release the download file, by delaying
1023 IN_PROC_BROWSER_TEST_F(DownloadContentTest, ShutdownAtRelease) {
1024 DownloadManagerImpl* download_manager(DownloadManagerForShell(shell()));
1026 // Mark delegate for delayed open.
1027 GetDownloadManagerDelegate()->SetDelayedOpen(true);
1029 // Setup new factory.
1030 DownloadFileWithDelayFactory* file_factory =
1031 new DownloadFileWithDelayFactory();
1032 download_manager->SetDownloadFileFactoryForTesting(
1033 scoped_ptr<DownloadFileFactory>(file_factory).Pass());
1035 // Create a download
1036 base::FilePath file(FILE_PATH_LITERAL("download-test.lib"));
1037 NavigateToURL(shell(), net::URLRequestMockHTTPJob::GetMockUrl(file));
1039 // Wait until the first (intermediate file) rename and execute the callback.
1040 file_factory->WaitForSomeCallback();
1041 std::vector<base::Closure> callbacks;
1042 file_factory->GetAllRenameCallbacks(&callbacks);
1043 ASSERT_EQ(1u, callbacks.size());
1047 // Wait until the second (final) rename callback is posted.
1048 file_factory->WaitForSomeCallback();
1049 file_factory->GetAllRenameCallbacks(&callbacks);
1050 ASSERT_EQ(1u, callbacks.size());
1056 // Confirm download isn't complete yet.
1057 std::vector<DownloadItem*> items;
1058 DownloadManagerForShell(shell())->GetAllDownloads(&items);
1059 EXPECT_EQ(DownloadItem::IN_PROGRESS, items[0]->GetState());
1061 // Cancel the download; confirm cancel fails anyway.
1062 ASSERT_EQ(1u, items.size());
1063 items[0]->Cancel(true);
1064 EXPECT_EQ(DownloadItem::IN_PROGRESS, items[0]->GetState());
1065 RunAllPendingInMessageLoop();
1066 EXPECT_EQ(DownloadItem::IN_PROGRESS, items[0]->GetState());
1068 MockDownloadItemObserver observer;
1069 items[0]->AddObserver(&observer);
1070 EXPECT_CALL(observer, OnDownloadDestroyed(items[0]));
1072 // Shutdown the download manager. Mostly this is confirming a lack of
1074 DownloadManagerForShell(shell())->Shutdown();
1077 IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeInterruptedDownload) {
1078 base::CommandLine::ForCurrentProcess()->AppendSwitch(
1079 switches::kEnableDownloadResumption);
1080 ASSERT_TRUE(test_server()->Start());
1082 GURL url = test_server()->GetURL(
1083 base::StringPrintf("rangereset?size=%d&rst_boundary=%d",
1084 GetSafeBufferChunk() * 3, GetSafeBufferChunk()));
1086 MockDownloadManagerObserver dm_observer(DownloadManagerForShell(shell()));
1087 EXPECT_CALL(dm_observer, OnDownloadCreated(_,_)).Times(1);
1089 DownloadItem* download(StartDownloadAndReturnItem(url));
1090 WaitForData(download, GetSafeBufferChunk());
1091 ::testing::Mock::VerifyAndClearExpectations(&dm_observer);
1093 // Confirm resumption while in progress doesn't do anything.
1095 ASSERT_EQ(GetSafeBufferChunk(), download->GetReceivedBytes());
1096 ASSERT_EQ(DownloadItem::IN_PROGRESS, download->GetState());
1098 // Tell the server to send the RST and confirm the interrupt happens.
1099 ReleaseRSTAndConfirmInterruptForResume(download);
1100 ConfirmFileStatusForResume(
1101 download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3,
1102 base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload")));
1104 // Resume, confirming received bytes on resumption is correct.
1105 // Make sure no creation calls are included.
1106 EXPECT_CALL(dm_observer, OnDownloadCreated(_,_)).Times(0);
1107 int initial_size = 0;
1108 DownloadUpdatedObserver initial_size_observer(
1109 download, base::Bind(&InitialSizeFilter, &initial_size));
1111 initial_size_observer.WaitForEvent();
1112 EXPECT_EQ(GetSafeBufferChunk(), initial_size);
1113 ::testing::Mock::VerifyAndClearExpectations(&dm_observer);
1115 // and wait for expected data.
1116 WaitForData(download, GetSafeBufferChunk() * 2);
1118 // Tell the server to send the RST and confirm the interrupt happens.
1119 ReleaseRSTAndConfirmInterruptForResume(download);
1120 ConfirmFileStatusForResume(
1121 download, true, GetSafeBufferChunk() * 2, GetSafeBufferChunk() * 3,
1122 base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload")));
1124 // Resume and wait for completion.
1125 DownloadUpdatedObserver completion_observer(
1126 download, base::Bind(DownloadCompleteFilter));
1128 completion_observer.WaitForEvent();
1130 ConfirmFileStatusForResume(
1131 download, true, GetSafeBufferChunk() * 3, GetSafeBufferChunk() * 3,
1132 base::FilePath(FILE_PATH_LITERAL("rangereset")));
1134 // Confirm resumption while complete doesn't do anything.
1136 ASSERT_EQ(GetSafeBufferChunk() * 3, download->GetReceivedBytes());
1137 ASSERT_EQ(DownloadItem::COMPLETE, download->GetState());
1138 RunAllPendingInMessageLoop();
1139 ASSERT_EQ(GetSafeBufferChunk() * 3, download->GetReceivedBytes());
1140 ASSERT_EQ(DownloadItem::COMPLETE, download->GetState());
1143 // Confirm restart fallback happens if a range request is bounced.
1144 IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeInterruptedDownloadNoRange) {
1145 base::CommandLine::ForCurrentProcess()->AppendSwitch(
1146 switches::kEnableDownloadResumption);
1147 ASSERT_TRUE(test_server()->Start());
1149 // Auto-restart if server doesn't handle ranges.
1150 GURL url = test_server()->GetURL(
1152 // First download hits an RST, rest don't, no ranges.
1153 "rangereset?size=%d&rst_boundary=%d&"
1154 "token=NoRange&rst_limit=1&bounce_range",
1155 GetSafeBufferChunk() * 3, GetSafeBufferChunk()));
1157 // Start the download and wait for first data chunk.
1158 DownloadItem* download(StartDownloadAndReturnItem(url));
1159 WaitForData(download, GetSafeBufferChunk());
1161 RecordingDownloadObserver recorder(download);
1163 ReleaseRSTAndConfirmInterruptForResume(download);
1164 ConfirmFileStatusForResume(
1165 download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3,
1166 base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload")));
1168 DownloadUpdatedObserver completion_observer(
1169 download, base::Bind(DownloadCompleteFilter));
1171 completion_observer.WaitForEvent();
1173 ConfirmFileStatusForResume(
1174 download, true, GetSafeBufferChunk() * 3, GetSafeBufferChunk() * 3,
1175 base::FilePath(FILE_PATH_LITERAL("rangereset")));
1177 static const RecordingDownloadObserver::RecordStruct expected_record[] = {
1179 {DownloadItem::INTERRUPTED, GetSafeBufferChunk()},
1180 // Starting continuation
1181 {DownloadItem::IN_PROGRESS, GetSafeBufferChunk()},
1182 // Notification of receiving whole file.
1183 {DownloadItem::IN_PROGRESS, 0},
1185 {DownloadItem::COMPLETE, GetSafeBufferChunk() * 3},
1188 recorder.CompareToExpectedRecord(expected_record, arraysize(expected_record));
1191 // Confirm restart fallback happens if a precondition is failed.
1192 IN_PROC_BROWSER_TEST_F(DownloadContentTest,
1193 ResumeInterruptedDownloadBadPrecondition) {
1194 base::CommandLine::ForCurrentProcess()->AppendSwitch(
1195 switches::kEnableDownloadResumption);
1196 ASSERT_TRUE(test_server()->Start());
1198 GURL url = test_server()->GetURL(base::StringPrintf(
1199 // First download hits an RST, rest don't, precondition fail.
1200 "rangereset?size=%d&rst_boundary=%d&"
1201 "token=BadPrecondition&rst_limit=1&fail_precondition=2",
1202 GetSafeBufferChunk() * 3,
1203 GetSafeBufferChunk()));
1205 // Start the download and wait for first data chunk.
1206 DownloadItem* download(StartDownloadAndReturnItem(url));
1207 WaitForData(download, GetSafeBufferChunk());
1209 RecordingDownloadObserver recorder(download);
1211 ReleaseRSTAndConfirmInterruptForResume(download);
1212 ConfirmFileStatusForResume(
1213 download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3,
1214 base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload")));
1215 EXPECT_EQ("BadPrecondition2", download->GetETag());
1217 DownloadUpdatedObserver completion_observer(
1218 download, base::Bind(DownloadCompleteFilter));
1220 completion_observer.WaitForEvent();
1222 ConfirmFileStatusForResume(
1223 download, true, GetSafeBufferChunk() * 3, GetSafeBufferChunk() * 3,
1224 base::FilePath(FILE_PATH_LITERAL("rangereset")));
1225 EXPECT_EQ("BadPrecondition0", download->GetETag());
1227 static const RecordingDownloadObserver::RecordStruct expected_record[] = {
1229 {DownloadItem::INTERRUPTED, GetSafeBufferChunk()},
1230 // Starting continuation
1231 {DownloadItem::IN_PROGRESS, GetSafeBufferChunk()},
1232 // Server precondition fail.
1233 {DownloadItem::INTERRUPTED, 0},
1234 // Notification of successful restart.
1235 {DownloadItem::IN_PROGRESS, 0},
1237 {DownloadItem::COMPLETE, GetSafeBufferChunk() * 3},
1240 recorder.CompareToExpectedRecord(expected_record, arraysize(expected_record));
1243 // Confirm we don't try to resume if we don't have a verifier.
1244 IN_PROC_BROWSER_TEST_F(DownloadContentTest,
1245 ResumeInterruptedDownloadNoVerifiers) {
1246 base::CommandLine::ForCurrentProcess()->AppendSwitch(
1247 switches::kEnableDownloadResumption);
1248 ASSERT_TRUE(test_server()->Start());
1250 GURL url = test_server()->GetURL(
1252 // First download hits an RST, rest don't, no verifiers.
1253 "rangereset?size=%d&rst_boundary=%d&"
1254 "token=NoRange&rst_limit=1&no_verifiers",
1255 GetSafeBufferChunk() * 3, GetSafeBufferChunk()));
1257 // Start the download and wait for first data chunk.
1258 DownloadItem* download(StartDownloadAndReturnItem(url));
1259 WaitForData(download, GetSafeBufferChunk());
1261 RecordingDownloadObserver recorder(download);
1263 ReleaseRSTAndConfirmInterruptForResume(download);
1264 ConfirmFileStatusForResume(
1265 download, false, GetSafeBufferChunk(), GetSafeBufferChunk() * 3,
1268 DownloadUpdatedObserver completion_observer(
1269 download, base::Bind(DownloadCompleteFilter));
1271 completion_observer.WaitForEvent();
1273 ConfirmFileStatusForResume(
1274 download, true, GetSafeBufferChunk() * 3, GetSafeBufferChunk() * 3,
1275 base::FilePath(FILE_PATH_LITERAL("rangereset")));
1277 static const RecordingDownloadObserver::RecordStruct expected_record[] = {
1279 {DownloadItem::INTERRUPTED, GetSafeBufferChunk()},
1280 // Restart for lack of verifiers
1281 {DownloadItem::IN_PROGRESS, 0},
1283 {DownloadItem::COMPLETE, GetSafeBufferChunk() * 3},
1286 recorder.CompareToExpectedRecord(expected_record, arraysize(expected_record));
1289 IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeWithDeletedFile) {
1290 base::CommandLine::ForCurrentProcess()->AppendSwitch(
1291 switches::kEnableDownloadResumption);
1292 ASSERT_TRUE(test_server()->Start());
1294 GURL url = test_server()->GetURL(
1296 // First download hits an RST, rest don't
1297 "rangereset?size=%d&rst_boundary=%d&"
1298 "token=NoRange&rst_limit=1",
1299 GetSafeBufferChunk() * 3, GetSafeBufferChunk()));
1301 // Start the download and wait for first data chunk.
1302 DownloadItem* download(StartDownloadAndReturnItem(url));
1303 WaitForData(download, GetSafeBufferChunk());
1305 RecordingDownloadObserver recorder(download);
1307 ReleaseRSTAndConfirmInterruptForResume(download);
1308 ConfirmFileStatusForResume(
1309 download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3,
1310 base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload")));
1312 // Delete the intermediate file.
1313 base::DeleteFile(download->GetFullPath(), false);
1315 DownloadUpdatedObserver completion_observer(
1316 download, base::Bind(DownloadCompleteFilter));
1318 completion_observer.WaitForEvent();
1320 ConfirmFileStatusForResume(
1321 download, true, GetSafeBufferChunk() * 3, GetSafeBufferChunk() * 3,
1322 base::FilePath(FILE_PATH_LITERAL("rangereset")));
1324 static const RecordingDownloadObserver::RecordStruct expected_record[] = {
1326 {DownloadItem::INTERRUPTED, GetSafeBufferChunk()},
1327 // Starting continuation
1328 {DownloadItem::IN_PROGRESS, GetSafeBufferChunk()},
1329 // Error because file isn't there.
1330 {DownloadItem::INTERRUPTED, 0},
1332 {DownloadItem::IN_PROGRESS, 0},
1334 {DownloadItem::COMPLETE, GetSafeBufferChunk() * 3},
1337 recorder.CompareToExpectedRecord(expected_record, arraysize(expected_record));
1340 IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeWithFileInitError) {
1341 base::CommandLine::ForCurrentProcess()->AppendSwitch(
1342 switches::kEnableDownloadResumption);
1343 base::FilePath file(FILE_PATH_LITERAL("download-test.lib"));
1344 GURL url(net::URLRequestMockHTTPJob::GetMockUrl(file));
1346 // Setup the error injector.
1347 scoped_refptr<TestFileErrorInjector> injector(
1348 TestFileErrorInjector::Create(DownloadManagerForShell(shell())));
1350 TestFileErrorInjector::FileErrorInfo err = {
1352 TestFileErrorInjector::FILE_OPERATION_INITIALIZE,
1354 DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE
1356 injector->AddError(err);
1357 injector->InjectErrors();
1359 // Start and watch for interrupt.
1360 scoped_ptr<DownloadTestObserver> int_observer(
1361 CreateInterruptedWaiter(shell(), 1));
1362 DownloadItem* download(StartDownloadAndReturnItem(url));
1363 int_observer->WaitForFinished();
1364 ASSERT_EQ(DownloadItem::INTERRUPTED, download->GetState());
1365 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE,
1366 download->GetLastReason());
1367 EXPECT_EQ(0, download->GetReceivedBytes());
1368 EXPECT_TRUE(download->GetFullPath().empty());
1369 EXPECT_TRUE(download->GetTargetFilePath().empty());
1371 // We need to make sure that any cross-thread downloads communication has
1372 // quiesced before clearing and injecting the new errors, as the
1373 // InjectErrors() routine alters the currently in use download file
1374 // factory, which is a file thread object.
1375 RunAllPendingInMessageLoop(BrowserThread::FILE);
1376 RunAllPendingInMessageLoop();
1378 // Clear the old errors list.
1379 injector->ClearErrors();
1380 injector->InjectErrors();
1382 // Resume and watch completion.
1383 DownloadUpdatedObserver completion_observer(
1384 download, base::Bind(DownloadCompleteFilter));
1386 completion_observer.WaitForEvent();
1387 EXPECT_EQ(download->GetState(), DownloadItem::COMPLETE);
1390 IN_PROC_BROWSER_TEST_F(DownloadContentTest,
1391 ResumeWithFileIntermediateRenameError) {
1392 base::CommandLine::ForCurrentProcess()->AppendSwitch(
1393 switches::kEnableDownloadResumption);
1394 base::FilePath file(FILE_PATH_LITERAL("download-test.lib"));
1395 GURL url(net::URLRequestMockHTTPJob::GetMockUrl(file));
1397 // Setup the error injector.
1398 scoped_refptr<TestFileErrorInjector> injector(
1399 TestFileErrorInjector::Create(DownloadManagerForShell(shell())));
1401 TestFileErrorInjector::FileErrorInfo err = {
1403 TestFileErrorInjector::FILE_OPERATION_RENAME_UNIQUIFY,
1405 DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE
1407 injector->AddError(err);
1408 injector->InjectErrors();
1410 // Start and watch for interrupt.
1411 scoped_ptr<DownloadTestObserver> int_observer(
1412 CreateInterruptedWaiter(shell(), 1));
1413 DownloadItem* download(StartDownloadAndReturnItem(url));
1414 int_observer->WaitForFinished();
1415 ASSERT_EQ(DownloadItem::INTERRUPTED, download->GetState());
1416 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE,
1417 download->GetLastReason());
1418 EXPECT_TRUE(download->GetFullPath().empty());
1419 // Target path will have been set after file name determination. GetFullPath()
1420 // being empty is sufficient to signal that filename determination needs to be
1422 EXPECT_FALSE(download->GetTargetFilePath().empty());
1424 // We need to make sure that any cross-thread downloads communication has
1425 // quiesced before clearing and injecting the new errors, as the
1426 // InjectErrors() routine alters the currently in use download file
1427 // factory, which is a file thread object.
1428 RunAllPendingInMessageLoop(BrowserThread::FILE);
1429 RunAllPendingInMessageLoop();
1431 // Clear the old errors list.
1432 injector->ClearErrors();
1433 injector->InjectErrors();
1435 // Resume and watch completion.
1436 DownloadUpdatedObserver completion_observer(
1437 download, base::Bind(DownloadCompleteFilter));
1439 completion_observer.WaitForEvent();
1440 EXPECT_EQ(download->GetState(), DownloadItem::COMPLETE);
1443 IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeWithFileFinalRenameError) {
1444 base::CommandLine::ForCurrentProcess()->AppendSwitch(
1445 switches::kEnableDownloadResumption);
1446 base::FilePath file(FILE_PATH_LITERAL("download-test.lib"));
1447 GURL url(net::URLRequestMockHTTPJob::GetMockUrl(file));
1449 // Setup the error injector.
1450 scoped_refptr<TestFileErrorInjector> injector(
1451 TestFileErrorInjector::Create(DownloadManagerForShell(shell())));
1453 DownloadManagerForShell(shell())->RemoveAllDownloads();
1454 TestFileErrorInjector::FileErrorInfo err = {
1456 TestFileErrorInjector::FILE_OPERATION_RENAME_ANNOTATE,
1458 DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE
1460 injector->AddError(err);
1461 injector->InjectErrors();
1463 // Start and watch for interrupt.
1464 scoped_ptr<DownloadTestObserver> int_observer(
1465 CreateInterruptedWaiter(shell(), 1));
1466 DownloadItem* download(StartDownloadAndReturnItem(url));
1467 int_observer->WaitForFinished();
1468 ASSERT_EQ(DownloadItem::INTERRUPTED, download->GetState());
1469 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE,
1470 download->GetLastReason());
1471 EXPECT_TRUE(download->GetFullPath().empty());
1472 // Target path should still be intact.
1473 EXPECT_FALSE(download->GetTargetFilePath().empty());
1475 // We need to make sure that any cross-thread downloads communication has
1476 // quiesced before clearing and injecting the new errors, as the
1477 // InjectErrors() routine alters the currently in use download file
1478 // factory, which is a file thread object.
1479 RunAllPendingInMessageLoop(BrowserThread::FILE);
1480 RunAllPendingInMessageLoop();
1482 // Clear the old errors list.
1483 injector->ClearErrors();
1484 injector->InjectErrors();
1486 // Resume and watch completion.
1487 DownloadUpdatedObserver completion_observer(
1488 download, base::Bind(DownloadCompleteFilter));
1490 completion_observer.WaitForEvent();
1491 EXPECT_EQ(download->GetState(), DownloadItem::COMPLETE);
1494 // An interrupted download should remove the intermediate file when it is
1496 IN_PROC_BROWSER_TEST_F(DownloadContentTest, CancelInterruptedDownload) {
1497 base::CommandLine::ForCurrentProcess()->AppendSwitch(
1498 switches::kEnableDownloadResumption);
1499 ASSERT_TRUE(test_server()->Start());
1501 GURL url1 = test_server()->GetURL(
1502 base::StringPrintf("rangereset?size=%d&rst_boundary=%d",
1503 GetSafeBufferChunk() * 3, GetSafeBufferChunk()));
1505 DownloadItem* download(StartDownloadAndReturnItem(url1));
1506 WaitForData(download, GetSafeBufferChunk());
1508 ReleaseRSTAndConfirmInterruptForResume(download);
1509 ConfirmFileStatusForResume(
1510 download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3,
1511 base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload")));
1513 base::FilePath intermediate_path(download->GetFullPath());
1514 ASSERT_FALSE(intermediate_path.empty());
1515 EXPECT_TRUE(base::PathExists(intermediate_path));
1517 download->Cancel(true /* user_cancel */);
1518 RunAllPendingInMessageLoop(BrowserThread::FILE);
1519 RunAllPendingInMessageLoop();
1521 // The intermediate file should now be gone.
1522 EXPECT_FALSE(base::PathExists(intermediate_path));
1523 EXPECT_TRUE(download->GetFullPath().empty());
1526 IN_PROC_BROWSER_TEST_F(DownloadContentTest, RemoveDownload) {
1527 base::CommandLine::ForCurrentProcess()->AppendSwitch(
1528 switches::kEnableDownloadResumption);
1529 ASSERT_TRUE(test_server()->Start());
1531 // An interrupted download should remove the intermediate file when it is
1534 GURL url1 = test_server()->GetURL(
1535 base::StringPrintf("rangereset?size=%d&rst_boundary=%d",
1536 GetSafeBufferChunk() * 3, GetSafeBufferChunk()));
1538 DownloadItem* download(StartDownloadAndReturnItem(url1));
1539 WaitForData(download, GetSafeBufferChunk());
1540 ReleaseRSTAndConfirmInterruptForResume(download);
1541 ConfirmFileStatusForResume(
1542 download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3,
1543 base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload")));
1545 base::FilePath intermediate_path(download->GetFullPath());
1546 ASSERT_FALSE(intermediate_path.empty());
1547 EXPECT_TRUE(base::PathExists(intermediate_path));
1550 RunAllPendingInMessageLoop(BrowserThread::FILE);
1551 RunAllPendingInMessageLoop();
1553 // The intermediate file should now be gone.
1554 EXPECT_FALSE(base::PathExists(intermediate_path));
1557 // A completed download shouldn't delete the downloaded file when it is
1560 // Start the second download and wait until it's done.
1561 base::FilePath file2(FILE_PATH_LITERAL("download-test.lib"));
1562 GURL url2(net::URLRequestMockHTTPJob::GetMockUrl(file2));
1563 scoped_ptr<DownloadTestObserver> completion_observer(
1564 CreateWaiter(shell(), 1));
1565 DownloadItem* download(StartDownloadAndReturnItem(url2));
1566 completion_observer->WaitForFinished();
1568 // The target path should exist.
1569 base::FilePath target_path(download->GetTargetFilePath());
1570 EXPECT_TRUE(base::PathExists(target_path));
1572 RunAllPendingInMessageLoop(BrowserThread::FILE);
1573 RunAllPendingInMessageLoop();
1575 // The file should still exist.
1576 EXPECT_TRUE(base::PathExists(target_path));
1580 IN_PROC_BROWSER_TEST_F(DownloadContentTest, RemoveResumingDownload) {
1581 SetupEnsureNoPendingDownloads();
1582 base::CommandLine::ForCurrentProcess()->AppendSwitch(
1583 switches::kEnableDownloadResumption);
1584 ASSERT_TRUE(test_server()->Start());
1586 GURL url = test_server()->GetURL(
1587 base::StringPrintf("rangereset?size=%d&rst_boundary=%d",
1588 GetSafeBufferChunk() * 3, GetSafeBufferChunk()));
1590 MockDownloadManagerObserver dm_observer(DownloadManagerForShell(shell()));
1591 EXPECT_CALL(dm_observer, OnDownloadCreated(_,_)).Times(1);
1593 DownloadItem* download(StartDownloadAndReturnItem(url));
1594 WaitForData(download, GetSafeBufferChunk());
1595 ::testing::Mock::VerifyAndClearExpectations(&dm_observer);
1597 // Tell the server to send the RST and confirm the interrupt happens.
1598 ReleaseRSTAndConfirmInterruptForResume(download);
1599 ConfirmFileStatusForResume(
1600 download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3,
1601 base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload")));
1603 base::FilePath intermediate_path(download->GetFullPath());
1604 ASSERT_FALSE(intermediate_path.empty());
1605 EXPECT_TRUE(base::PathExists(intermediate_path));
1607 // Resume and remove download. We expect only a single OnDownloadCreated()
1608 // call, and that's for the second download created below.
1609 EXPECT_CALL(dm_observer, OnDownloadCreated(_,_)).Times(1);
1613 // The intermediate file should now be gone.
1614 RunAllPendingInMessageLoop(BrowserThread::FILE);
1615 RunAllPendingInMessageLoop();
1616 EXPECT_FALSE(base::PathExists(intermediate_path));
1618 // Start the second download and wait until it's done. The test server is
1619 // single threaded. The response to this download request should follow the
1620 // response to the previous resumption request.
1621 GURL url2(test_server()->GetURL("rangereset?size=100&rst_limit=0&token=x"));
1622 NavigateToURLAndWaitForDownload(shell(), url2, DownloadItem::COMPLETE);
1624 EXPECT_TRUE(EnsureNoPendingDownloads());
1627 IN_PROC_BROWSER_TEST_F(DownloadContentTest, CancelResumingDownload) {
1628 SetupEnsureNoPendingDownloads();
1629 base::CommandLine::ForCurrentProcess()->AppendSwitch(
1630 switches::kEnableDownloadResumption);
1631 ASSERT_TRUE(test_server()->Start());
1633 GURL url = test_server()->GetURL(
1634 base::StringPrintf("rangereset?size=%d&rst_boundary=%d",
1635 GetSafeBufferChunk() * 3, GetSafeBufferChunk()));
1637 MockDownloadManagerObserver dm_observer(DownloadManagerForShell(shell()));
1638 EXPECT_CALL(dm_observer, OnDownloadCreated(_,_)).Times(1);
1640 DownloadItem* download(StartDownloadAndReturnItem(url));
1641 WaitForData(download, GetSafeBufferChunk());
1642 ::testing::Mock::VerifyAndClearExpectations(&dm_observer);
1644 // Tell the server to send the RST and confirm the interrupt happens.
1645 ReleaseRSTAndConfirmInterruptForResume(download);
1646 ConfirmFileStatusForResume(
1647 download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3,
1648 base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload")));
1650 base::FilePath intermediate_path(download->GetFullPath());
1651 ASSERT_FALSE(intermediate_path.empty());
1652 EXPECT_TRUE(base::PathExists(intermediate_path));
1654 // Resume and cancel download. We expect only a single OnDownloadCreated()
1655 // call, and that's for the second download created below.
1656 EXPECT_CALL(dm_observer, OnDownloadCreated(_,_)).Times(1);
1658 download->Cancel(true);
1660 // The intermediate file should now be gone.
1661 RunAllPendingInMessageLoop(BrowserThread::FILE);
1662 RunAllPendingInMessageLoop();
1663 EXPECT_FALSE(base::PathExists(intermediate_path));
1664 EXPECT_TRUE(download->GetFullPath().empty());
1666 // Start the second download and wait until it's done. The test server is
1667 // single threaded. The response to this download request should follow the
1668 // response to the previous resumption request.
1669 GURL url2(test_server()->GetURL("rangereset?size=100&rst_limit=0&token=x"));
1670 NavigateToURLAndWaitForDownload(shell(), url2, DownloadItem::COMPLETE);
1672 EXPECT_TRUE(EnsureNoPendingDownloads());
1675 // Check that the cookie policy is correctly updated when downloading a file
1676 // that redirects cross origin.
1677 IN_PROC_BROWSER_TEST_F(DownloadContentTest, CookiePolicy) {
1678 ASSERT_TRUE(test_server()->Start());
1679 net::HostPortPair host_port = test_server()->host_port_pair();
1680 DCHECK_EQ(host_port.host(), std::string("127.0.0.1"));
1682 // Block third-party cookies.
1683 ShellNetworkDelegate::SetAcceptAllCookies(false);
1685 // |url| redirects to a different origin |download| which tries to set a
1687 std::string download(base::StringPrintf(
1688 "http://localhost:%d/set-cookie?A=B", host_port.port()));
1689 GURL url(test_server()->GetURL("server-redirect?" + download));
1691 // Download the file.
1692 SetupEnsureNoPendingDownloads();
1693 scoped_ptr<DownloadUrlParameters> dl_params(
1694 DownloadUrlParameters::FromWebContents(shell()->web_contents(), url));
1695 scoped_ptr<DownloadTestObserver> observer(CreateWaiter(shell(), 1));
1696 DownloadManagerForShell(shell())->DownloadUrl(dl_params.Pass());
1697 observer->WaitForFinished();
1699 // Get the important info from other threads and check it.
1700 EXPECT_TRUE(EnsureNoPendingDownloads());
1702 std::vector<DownloadItem*> downloads;
1703 DownloadManagerForShell(shell())->GetAllDownloads(&downloads);
1704 ASSERT_EQ(1u, downloads.size());
1705 ASSERT_EQ(DownloadItem::COMPLETE, downloads[0]->GetState());
1707 // Check that the cookies were correctly set.
1709 content::GetCookies(shell()->web_contents()->GetBrowserContext(),
1713 // A filename suggestion specified via a @download attribute should not be
1714 // effective if the final download URL is in another origin from the original
1716 IN_PROC_BROWSER_TEST_F(DownloadContentTest,
1717 DownloadAttributeCrossOriginRedirect) {
1718 EmbeddedTestServer origin_one;
1719 EmbeddedTestServer origin_two;
1720 ASSERT_TRUE(origin_one.InitializeAndWaitUntilReady());
1721 ASSERT_TRUE(origin_two.InitializeAndWaitUntilReady());
1723 // The download-attribute.html page contains an anchor element whose href is
1724 // set to the value of the query parameter (specified as |target| in the URL
1725 // below). The suggested filename for the anchor is 'suggested-filename'. When
1726 // the page is loaded, a script simulates a click on the anchor, triggering a
1727 // download of the target URL.
1729 // We construct two test servers; origin_one and origin_two. Once started, the
1730 // server URLs will differ by the port number. Therefore they will be in
1731 // different origins.
1732 GURL download_url = origin_one.GetURL("/ping");
1733 GURL referrer_url = origin_one.GetURL(
1734 std::string("/download-attribute.html?target=") + download_url.spec());
1736 // <origin_one>/download-attribute.html initiates a download of
1737 // <origin_one>/ping, which redirects to <origin_two>/download.
1738 origin_one.ServeFilesFromDirectory(GetTestFilePath("download", ""));
1739 origin_one.RegisterRequestHandler(
1740 CreateRedirectHandler("/ping", origin_two.GetURL("/download")));
1741 origin_two.RegisterRequestHandler(CreateBasicResponseHandler(
1742 "/download", "application/octet-stream", "Hello"));
1744 NavigateToURLAndWaitForDownload(
1745 shell(), referrer_url, DownloadItem::COMPLETE);
1747 std::vector<DownloadItem*> downloads;
1748 DownloadManagerForShell(shell())->GetAllDownloads(&downloads);
1749 ASSERT_EQ(1u, downloads.size());
1751 EXPECT_EQ(FILE_PATH_LITERAL("download"),
1752 downloads[0]->GetTargetFilePath().BaseName().value());
1753 ASSERT_TRUE(origin_one.ShutdownAndWaitUntilComplete());
1754 ASSERT_TRUE(origin_two.ShutdownAndWaitUntilComplete());
1757 // A filename suggestion specified via a @download attribute should be effective
1758 // if the final download URL is in the same origin as the initial download URL.
1759 // Test that this holds even if there are cross origin redirects in the middle
1760 // of the redirect chain.
1761 IN_PROC_BROWSER_TEST_F(DownloadContentTest,
1762 DownloadAttributeSameOriginRedirect) {
1763 EmbeddedTestServer origin_one;
1764 EmbeddedTestServer origin_two;
1765 ASSERT_TRUE(origin_one.InitializeAndWaitUntilReady());
1766 ASSERT_TRUE(origin_two.InitializeAndWaitUntilReady());
1768 // The download-attribute.html page contains an anchor element whose href is
1769 // set to the value of the query parameter (specified as |target| in the URL
1770 // below). The suggested filename for the anchor is 'suggested-filename'. When
1771 // the page is loaded, a script simulates a click on the anchor, triggering a
1772 // download of the target URL.
1774 // We construct two test servers; origin_one and origin_two. Once started, the
1775 // server URLs will differ by the port number. Therefore they will be in
1776 // different origins.
1777 GURL download_url = origin_one.GetURL("/ping");
1778 GURL referrer_url = origin_one.GetURL(
1779 std::string("/download-attribute.html?target=") + download_url.spec());
1780 origin_one.ServeFilesFromDirectory(GetTestFilePath("download", ""));
1782 // <origin_one>/download-attribute.html initiates a download of
1783 // <origin_one>/ping, which redirects to <origin_two>/pong, and then finally
1784 // to <origin_one>/download.
1785 origin_one.RegisterRequestHandler(
1786 CreateRedirectHandler("/ping", origin_two.GetURL("/pong")));
1787 origin_two.RegisterRequestHandler(
1788 CreateRedirectHandler("/pong", origin_one.GetURL("/download")));
1789 origin_one.RegisterRequestHandler(CreateBasicResponseHandler(
1790 "/download", "application/octet-stream", "Hello"));
1792 NavigateToURLAndWaitForDownload(
1793 shell(), referrer_url, DownloadItem::COMPLETE);
1795 std::vector<DownloadItem*> downloads;
1796 DownloadManagerForShell(shell())->GetAllDownloads(&downloads);
1797 ASSERT_EQ(1u, downloads.size());
1799 EXPECT_EQ(FILE_PATH_LITERAL("suggested-filename"),
1800 downloads[0]->GetTargetFilePath().BaseName().value());
1801 ASSERT_TRUE(origin_one.ShutdownAndWaitUntilComplete());
1802 ASSERT_TRUE(origin_two.ShutdownAndWaitUntilComplete());
1805 // The file empty.bin is served with a MIME type of application/octet-stream.
1806 // The content body is empty. Make sure this case is handled properly and we
1807 // don't regress on http://crbug.com/320394.
1808 IN_PROC_BROWSER_TEST_F(DownloadContentTest, DownloadGZipWithNoContent) {
1809 EmbeddedTestServer test_server;
1810 ASSERT_TRUE(test_server.InitializeAndWaitUntilReady());
1812 GURL url = test_server.GetURL("/empty.bin");
1813 test_server.ServeFilesFromDirectory(GetTestFilePath("download", ""));
1815 NavigateToURLAndWaitForDownload(shell(), url, DownloadItem::COMPLETE);
1816 // That's it. This should work without crashing.
1819 } // namespace content