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// 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.
7
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"
45#include "url/gurl.h"
46
47#if defined(ENABLE_PLUGINS)
48#include "content/browser/plugin_service_impl.h"
49#endif
50
51using ::net::test_server::EmbeddedTestServer;
52using ::testing::AllOf;
53using ::testing::Field;
54using ::testing::InSequence;
55using ::testing::Property;
56using ::testing::Return;
57using ::testing::StrictMock;
58using ::testing::_;
59
60namespace content {
61
62namespace {
63
64class MockDownloadItemObserver : public DownloadItem::Observer {
65 public:
66  MockDownloadItemObserver() {}
67  virtual ~MockDownloadItemObserver() {}
68
69  MOCK_METHOD1(OnDownloadUpdated, void(DownloadItem*));
70  MOCK_METHOD1(OnDownloadOpened, void(DownloadItem*));
71  MOCK_METHOD1(OnDownloadRemoved, void(DownloadItem*));
72  MOCK_METHOD1(OnDownloadDestroyed, void(DownloadItem*));
73};
74
75class MockDownloadManagerObserver : public DownloadManager::Observer {
76 public:
77  MockDownloadManagerObserver(DownloadManager* manager) {
78    manager_ = manager;
79    manager->AddObserver(this);
80  }
81  virtual ~MockDownloadManagerObserver() {
82    if (manager_)
83      manager_->RemoveObserver(this);
84  }
85
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);
91
92    manager_->RemoveObserver(this);
93    manager_ = NULL;
94  }
95
96  MOCK_METHOD1(MockManagerGoingDown, void(DownloadManager*));
97 private:
98  DownloadManager* manager_;
99};
100
101class DownloadFileWithDelayFactory;
102
103static 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()));
109}
110
111class DownloadFileWithDelay : public DownloadFileImpl {
112 public:
113  DownloadFileWithDelay(
114      scoped_ptr<DownloadSaveInfo> save_info,
115      const base::FilePath& default_download_directory,
116      const GURL& url,
117      const GURL& referrer_url,
118      bool calculate_hash,
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);
124
125  virtual ~DownloadFileWithDelay();
126
127  // Wraps DownloadFileImpl::Rename* and intercepts the return callback,
128  // storing it in the factory that produced this object for later
129  // retrieval.
130  virtual void RenameAndUniquify(
131      const base::FilePath& full_path,
132      const RenameCompletionCallback& callback) OVERRIDE;
133  virtual void RenameAndAnnotate(
134      const base::FilePath& full_path,
135      const RenameCompletionCallback& callback) OVERRIDE;
136
137 private:
138  static void RenameCallbackWrapper(
139      const base::WeakPtr<DownloadFileWithDelayFactory>& factory,
140      const RenameCompletionCallback& original_callback,
141      DownloadInterruptReason reason,
142      const base::FilePath& path);
143
144  // This variable may only be read on the FILE thread, and may only be
145  // indirected through (e.g. methods on DownloadFileWithDelayFactory called)
146  // on the UI thread.  This is because after construction,
147  // DownloadFileWithDelay lives on the file thread, but
148  // DownloadFileWithDelayFactory is purely a UI thread object.
149  base::WeakPtr<DownloadFileWithDelayFactory> owner_;
150
151  DISALLOW_COPY_AND_ASSIGN(DownloadFileWithDelay);
152};
153
154// All routines on this class must be called on the UI thread.
155class DownloadFileWithDelayFactory : public DownloadFileFactory {
156 public:
157  DownloadFileWithDelayFactory();
158  virtual ~DownloadFileWithDelayFactory();
159
160  // DownloadFileFactory interface.
161  virtual DownloadFile* CreateFile(
162      scoped_ptr<DownloadSaveInfo> save_info,
163      const base::FilePath& default_download_directory,
164      const GURL& url,
165      const GURL& referrer_url,
166      bool calculate_hash,
167      scoped_ptr<ByteStreamReader> stream,
168      const net::BoundNetLog& bound_net_log,
169      base::WeakPtr<DownloadDestinationObserver> observer) OVERRIDE;
170
171  void AddRenameCallback(base::Closure callback);
172  void GetAllRenameCallbacks(std::vector<base::Closure>* results);
173
174  // Do not return until GetAllRenameCallbacks() will return a non-empty list.
175  void WaitForSomeCallback();
176
177 private:
178  base::WeakPtrFactory<DownloadFileWithDelayFactory> weak_ptr_factory_;
179  std::vector<base::Closure> rename_callbacks_;
180  bool waiting_;
181
182  DISALLOW_COPY_AND_ASSIGN(DownloadFileWithDelayFactory);
183};
184
185DownloadFileWithDelay::DownloadFileWithDelay(
186    scoped_ptr<DownloadSaveInfo> save_info,
187    const base::FilePath& default_download_directory,
188    const GURL& url,
189    const GURL& referrer_url,
190    bool calculate_hash,
191    scoped_ptr<ByteStreamReader> stream,
192    const net::BoundNetLog& bound_net_log,
193    scoped_ptr<PowerSaveBlocker> power_save_blocker,
194    base::WeakPtr<DownloadDestinationObserver> observer,
195    base::WeakPtr<DownloadFileWithDelayFactory> owner)
196    : DownloadFileImpl(
197        save_info.Pass(), default_download_directory, url, referrer_url,
198        calculate_hash, stream.Pass(), bound_net_log, observer),
199      owner_(owner) {}
200
201DownloadFileWithDelay::~DownloadFileWithDelay() {}
202
203void DownloadFileWithDelay::RenameAndUniquify(
204    const base::FilePath& full_path,
205    const RenameCompletionCallback& callback) {
206  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
207  DownloadFileImpl::RenameAndUniquify(
208      full_path, base::Bind(DownloadFileWithDelay::RenameCallbackWrapper,
209                            owner_, callback));
210}
211
212void DownloadFileWithDelay::RenameAndAnnotate(
213    const base::FilePath& full_path, const RenameCompletionCallback& callback) {
214  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
215  DownloadFileImpl::RenameAndAnnotate(
216      full_path, base::Bind(DownloadFileWithDelay::RenameCallbackWrapper,
217                            owner_, callback));
218}
219
220// static
221void DownloadFileWithDelay::RenameCallbackWrapper(
222    const base::WeakPtr<DownloadFileWithDelayFactory>& factory,
223    const RenameCompletionCallback& original_callback,
224    DownloadInterruptReason reason,
225    const base::FilePath& path) {
226  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
227  if (!factory)
228    return;
229  factory->AddRenameCallback(base::Bind(original_callback, reason, path));
230}
231
232DownloadFileWithDelayFactory::DownloadFileWithDelayFactory()
233    : weak_ptr_factory_(this),
234      waiting_(false) {}
235DownloadFileWithDelayFactory::~DownloadFileWithDelayFactory() {}
236
237DownloadFile* DownloadFileWithDelayFactory::CreateFile(
238    scoped_ptr<DownloadSaveInfo> save_info,
239    const base::FilePath& default_download_directory,
240    const GURL& url,
241    const GURL& referrer_url,
242    bool calculate_hash,
243    scoped_ptr<ByteStreamReader> stream,
244    const net::BoundNetLog& bound_net_log,
245    base::WeakPtr<DownloadDestinationObserver> observer) {
246  scoped_ptr<PowerSaveBlocker> psb(
247      PowerSaveBlocker::Create(
248          PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
249          "Download in progress"));
250  return new DownloadFileWithDelay(
251      save_info.Pass(), default_download_directory, url, referrer_url,
252      calculate_hash, stream.Pass(), bound_net_log,
253      psb.Pass(), observer, weak_ptr_factory_.GetWeakPtr());
254}
255
256void DownloadFileWithDelayFactory::AddRenameCallback(base::Closure callback) {
257  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
258  rename_callbacks_.push_back(callback);
259  if (waiting_)
260    base::MessageLoopForUI::current()->Quit();
261}
262
263void DownloadFileWithDelayFactory::GetAllRenameCallbacks(
264    std::vector<base::Closure>* results) {
265  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
266  results->swap(rename_callbacks_);
267}
268
269void DownloadFileWithDelayFactory::WaitForSomeCallback() {
270  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
271
272  if (rename_callbacks_.empty()) {
273    waiting_ = true;
274    RunMessageLoop();
275    waiting_ = false;
276  }
277}
278
279class CountingDownloadFile : public DownloadFileImpl {
280 public:
281  CountingDownloadFile(
282    scoped_ptr<DownloadSaveInfo> save_info,
283    const base::FilePath& default_downloads_directory,
284    const GURL& url,
285    const GURL& referrer_url,
286    bool calculate_hash,
287    scoped_ptr<ByteStreamReader> stream,
288    const net::BoundNetLog& bound_net_log,
289    scoped_ptr<PowerSaveBlocker> power_save_blocker,
290    base::WeakPtr<DownloadDestinationObserver> observer)
291      : DownloadFileImpl(save_info.Pass(), default_downloads_directory,
292                         url, referrer_url, calculate_hash,
293                         stream.Pass(), bound_net_log, observer) {}
294
295  virtual ~CountingDownloadFile() {
296    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
297    active_files_--;
298  }
299
300  virtual void Initialize(const InitializeCallback& callback) OVERRIDE {
301    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
302    active_files_++;
303    return DownloadFileImpl::Initialize(callback);
304  }
305
306  static void GetNumberActiveFiles(int* result) {
307    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
308    *result = active_files_;
309  }
310
311  // Can be called on any thread, and will block (running message loop)
312  // until data is returned.
313  static int GetNumberActiveFilesFromFileThread() {
314    int result = -1;
315    BrowserThread::PostTaskAndReply(
316        BrowserThread::FILE,
317        FROM_HERE,
318        base::Bind(&CountingDownloadFile::GetNumberActiveFiles, &result),
319        base::MessageLoop::current()->QuitClosure());
320    base::MessageLoop::current()->Run();
321    DCHECK_NE(-1, result);
322    return result;
323  }
324
325 private:
326  static int active_files_;
327};
328
329int CountingDownloadFile::active_files_ = 0;
330
331class CountingDownloadFileFactory : public DownloadFileFactory {
332 public:
333  CountingDownloadFileFactory() {}
334  virtual ~CountingDownloadFileFactory() {}
335
336  // DownloadFileFactory interface.
337  virtual DownloadFile* CreateFile(
338    scoped_ptr<DownloadSaveInfo> save_info,
339    const base::FilePath& default_downloads_directory,
340    const GURL& url,
341    const GURL& referrer_url,
342    bool calculate_hash,
343    scoped_ptr<ByteStreamReader> stream,
344    const net::BoundNetLog& bound_net_log,
345    base::WeakPtr<DownloadDestinationObserver> observer) OVERRIDE {
346    scoped_ptr<PowerSaveBlocker> psb(
347        PowerSaveBlocker::Create(
348            PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
349            "Download in progress"));
350    return new CountingDownloadFile(
351        save_info.Pass(), default_downloads_directory, url, referrer_url,
352        calculate_hash, stream.Pass(), bound_net_log,
353        psb.Pass(), observer);
354  }
355};
356
357class TestShellDownloadManagerDelegate : public ShellDownloadManagerDelegate {
358 public:
359  TestShellDownloadManagerDelegate()
360      : delay_download_open_(false) {}
361  virtual ~TestShellDownloadManagerDelegate() {}
362
363  virtual bool ShouldOpenDownload(
364      DownloadItem* item,
365      const DownloadOpenDelayedCallback& callback) OVERRIDE {
366    if (delay_download_open_) {
367      delayed_callbacks_.push_back(callback);
368      return false;
369    }
370    return true;
371  }
372
373  void SetDelayedOpen(bool delay) {
374    delay_download_open_ = delay;
375  }
376
377  void GetDelayedCallbacks(
378      std::vector<DownloadOpenDelayedCallback>* callbacks) {
379    callbacks->swap(delayed_callbacks_);
380  }
381 private:
382  bool delay_download_open_;
383  std::vector<DownloadOpenDelayedCallback> delayed_callbacks_;
384};
385
386// Record all state transitions and byte counts on the observed download.
387class RecordingDownloadObserver : DownloadItem::Observer {
388 public:
389  struct RecordStruct {
390    DownloadItem::DownloadState state;
391    int bytes_received;
392  };
393
394  typedef std::vector<RecordStruct> RecordVector;
395
396  RecordingDownloadObserver(DownloadItem* download)
397      : download_(download) {
398    last_state_.state = download->GetState();
399    last_state_.bytes_received = download->GetReceivedBytes();
400    download_->AddObserver(this);
401  }
402
403  virtual ~RecordingDownloadObserver() {
404    RemoveObserver();
405  }
406
407  void CompareToExpectedRecord(const RecordStruct expected[], size_t size) {
408    EXPECT_EQ(size, record_.size());
409    int min = size > record_.size() ? record_.size() : size;
410    for (int i = 0; i < min; ++i) {
411      EXPECT_EQ(expected[i].state, record_[i].state) << "Iteration " << i;
412      EXPECT_EQ(expected[i].bytes_received, record_[i].bytes_received)
413          << "Iteration " << i;
414    }
415  }
416
417 private:
418  virtual void OnDownloadUpdated(DownloadItem* download) OVERRIDE {
419    DCHECK_EQ(download_, download);
420    DownloadItem::DownloadState state = download->GetState();
421    int bytes = download->GetReceivedBytes();
422    if (last_state_.state != state || last_state_.bytes_received > bytes) {
423      last_state_.state = state;
424      last_state_.bytes_received = bytes;
425      record_.push_back(last_state_);
426    }
427  }
428
429  virtual void OnDownloadDestroyed(DownloadItem* download) OVERRIDE {
430    DCHECK_EQ(download_, download);
431    RemoveObserver();
432  }
433
434  void RemoveObserver() {
435    if (download_) {
436      download_->RemoveObserver(this);
437      download_ = NULL;
438    }
439  }
440
441  DownloadItem* download_;
442  RecordStruct last_state_;
443  RecordVector record_;
444};
445
446// Get the next created download.
447class DownloadCreateObserver : DownloadManager::Observer {
448 public:
449  DownloadCreateObserver(DownloadManager* manager)
450      : manager_(manager),
451        item_(NULL),
452        waiting_(false) {
453    manager_->AddObserver(this);
454  }
455
456  virtual ~DownloadCreateObserver() {
457    if (manager_)
458      manager_->RemoveObserver(this);
459    manager_ = NULL;
460  }
461
462  virtual void ManagerGoingDown(DownloadManager* manager) OVERRIDE {
463    DCHECK_EQ(manager_, manager);
464    manager_->RemoveObserver(this);
465    manager_ = NULL;
466  }
467
468  virtual void OnDownloadCreated(DownloadManager* manager,
469                                 DownloadItem* download) OVERRIDE {
470    if (!item_)
471      item_ = download;
472
473    if (waiting_)
474      base::MessageLoopForUI::current()->Quit();
475  }
476
477  DownloadItem* WaitForFinished() {
478    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
479    if (!item_) {
480      waiting_ = true;
481      RunMessageLoop();
482      waiting_ = false;
483    }
484    return item_;
485  }
486
487 private:
488  DownloadManager* manager_;
489  DownloadItem* item_;
490  bool waiting_;
491};
492
493
494// Filter for waiting for a certain number of bytes.
495bool DataReceivedFilter(int number_of_bytes, DownloadItem* download) {
496  return download->GetReceivedBytes() >= number_of_bytes;
497}
498
499// Filter for download completion.
500bool DownloadCompleteFilter(DownloadItem* download) {
501  return download->GetState() == DownloadItem::COMPLETE;
502}
503
504// Filter for saving the size of the download when the first IN_PROGRESS
505// is hit.
506bool InitialSizeFilter(int* download_size, DownloadItem* download) {
507  if (download->GetState() != DownloadItem::IN_PROGRESS)
508    return false;
509
510  *download_size = download->GetReceivedBytes();
511  return true;
512}
513
514// Request handler to be used with CreateRedirectHandler().
515scoped_ptr<net::test_server::HttpResponse> HandleRequestAndSendRedirectResponse(
516    const std::string& relative_url,
517    const GURL& target_url,
518    const net::test_server::HttpRequest& request) {
519  scoped_ptr<net::test_server::BasicHttpResponse> response;
520  if (request.relative_url == relative_url) {
521    response.reset(new net::test_server::BasicHttpResponse);
522    response->set_code(net::HTTP_FOUND);
523    response->AddCustomHeader("Location", target_url.spec());
524  }
525  return response.PassAs<net::test_server::HttpResponse>();
526}
527
528// Creates a request handler for EmbeddedTestServer that responds with a HTTP
529// 302 redirect if the request URL matches |relative_url|.
530EmbeddedTestServer::HandleRequestCallback CreateRedirectHandler(
531    const std::string& relative_url,
532    const GURL& target_url) {
533  return base::Bind(
534      &HandleRequestAndSendRedirectResponse, relative_url, target_url);
535}
536
537// Request handler to be used with CreateBasicResponseHandler().
538scoped_ptr<net::test_server::HttpResponse> HandleRequestAndSendBasicResponse(
539    const std::string& relative_url,
540    const std::string& content_type,
541    const std::string& body,
542    const net::test_server::HttpRequest& request) {
543  scoped_ptr<net::test_server::BasicHttpResponse> response;
544  if (request.relative_url == relative_url) {
545    response.reset(new net::test_server::BasicHttpResponse);
546    response->set_content_type(content_type);
547    response->set_content(body);
548  }
549  return response.PassAs<net::test_server::HttpResponse>();
550}
551
552// Creates a request handler for an EmbeddedTestServer that response with an
553// HTTP 200 status code, a Content-Type header and a body.
554EmbeddedTestServer::HandleRequestCallback CreateBasicResponseHandler(
555    const std::string& relative_url,
556    const std::string& content_type,
557    const std::string& body) {
558  return base::Bind(
559      &HandleRequestAndSendBasicResponse, relative_url, content_type, body);
560}
561
562}  // namespace
563
564class DownloadContentTest : public ContentBrowserTest {
565 protected:
566  // An initial send from a website of at least this size will not be
567  // help up by buffering in the underlying downloads ByteStream data
568  // transfer.  This is important because on resumption tests we wait
569  // until we've gotten the data we expect before allowing the test server
570  // to send its reset, to get around hard close semantics on the Windows
571  // socket layer implementation.
572  int GetSafeBufferChunk() const {
573    return (DownloadResourceHandler::kDownloadByteStreamSize /
574       ByteStreamWriter::kFractionBufferBeforeSending) + 1;
575  }
576
577  virtual void SetUpOnMainThread() OVERRIDE {
578    ASSERT_TRUE(downloads_directory_.CreateUniqueTempDir());
579
580    test_delegate_.reset(new TestShellDownloadManagerDelegate());
581    test_delegate_->SetDownloadBehaviorForTesting(downloads_directory_.path());
582    DownloadManager* manager = DownloadManagerForShell(shell());
583    manager->GetDelegate()->Shutdown();
584    manager->SetDelegate(test_delegate_.get());
585    test_delegate_->SetDownloadManager(manager);
586
587    BrowserThread::PostTask(
588        BrowserThread::IO, FROM_HERE,
589        base::Bind(&URLRequestSlowDownloadJob::AddUrlHandler));
590    base::FilePath mock_base(GetTestFilePath("download", ""));
591    BrowserThread::PostTask(
592        BrowserThread::IO,
593        FROM_HERE,
594        base::Bind(
595            &net::URLRequestMockHTTPJob::AddUrlHandler,
596            mock_base,
597            make_scoped_refptr(content::BrowserThread::GetBlockingPool())));
598  }
599
600  TestShellDownloadManagerDelegate* GetDownloadManagerDelegate() {
601    return test_delegate_.get();
602  }
603
604  // Create a DownloadTestObserverTerminal that will wait for the
605  // specified number of downloads to finish.
606  DownloadTestObserver* CreateWaiter(
607      Shell* shell, int num_downloads) {
608    DownloadManager* download_manager = DownloadManagerForShell(shell);
609    return new DownloadTestObserverTerminal(download_manager, num_downloads,
610        DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL);
611  }
612
613  // Create a DownloadTestObserverInProgress that will wait for the
614  // specified number of downloads to start.
615  DownloadCreateObserver* CreateInProgressWaiter(
616      Shell* shell, int num_downloads) {
617    DownloadManager* download_manager = DownloadManagerForShell(shell);
618    return new DownloadCreateObserver(download_manager);
619  }
620
621  DownloadTestObserver* CreateInterruptedWaiter(
622      Shell* shell, int num_downloads) {
623    DownloadManager* download_manager = DownloadManagerForShell(shell);
624    return new DownloadTestObserverInterrupted(download_manager, num_downloads,
625        DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL);
626  }
627
628  // Note: Cannot be used with other alternative DownloadFileFactorys
629  void SetupEnsureNoPendingDownloads() {
630    DownloadManagerForShell(shell())->SetDownloadFileFactoryForTesting(
631        scoped_ptr<DownloadFileFactory>(
632            new CountingDownloadFileFactory()).Pass());
633  }
634
635  bool EnsureNoPendingDownloads() {
636    bool result = true;
637    BrowserThread::PostTask(
638        BrowserThread::IO, FROM_HERE,
639        base::Bind(&EnsureNoPendingDownloadJobsOnIO, &result));
640    base::MessageLoop::current()->Run();
641    return result &&
642           (CountingDownloadFile::GetNumberActiveFilesFromFileThread() == 0);
643  }
644
645  void NavigateToURLAndWaitForDownload(
646      Shell* shell,
647      const GURL& url,
648      DownloadItem::DownloadState expected_terminal_state) {
649    scoped_ptr<DownloadTestObserver> observer(CreateWaiter(shell, 1));
650    NavigateToURL(shell, url);
651    observer->WaitForFinished();
652    EXPECT_EQ(1u, observer->NumDownloadsSeenInState(expected_terminal_state));
653  }
654
655  // Checks that |path| is has |file_size| bytes, and matches the |value|
656  // string.
657  bool VerifyFile(const base::FilePath& path,
658                  const std::string& value,
659                  const int64 file_size) {
660    std::string file_contents;
661
662    bool read = base::ReadFileToString(path, &file_contents);
663    EXPECT_TRUE(read) << "Failed reading file: " << path.value() << std::endl;
664    if (!read)
665      return false;  // Couldn't read the file.
666
667    // Note: we don't handle really large files (more than size_t can hold)
668    // so we will fail in that case.
669    size_t expected_size = static_cast<size_t>(file_size);
670
671    // Check the size.
672    EXPECT_EQ(expected_size, file_contents.size());
673    if (expected_size != file_contents.size())
674      return false;
675
676    // Check the contents.
677    EXPECT_EQ(value, file_contents);
678    if (memcmp(file_contents.c_str(), value.c_str(), expected_size) != 0)
679      return false;
680
681    return true;
682  }
683
684  // Start a download and return the item.
685  DownloadItem* StartDownloadAndReturnItem(GURL url) {
686    scoped_ptr<DownloadCreateObserver> observer(
687        CreateInProgressWaiter(shell(), 1));
688    NavigateToURL(shell(), url);
689    observer->WaitForFinished();
690    std::vector<DownloadItem*> downloads;
691    DownloadManagerForShell(shell())->GetAllDownloads(&downloads);
692    EXPECT_EQ(1u, downloads.size());
693    if (1u != downloads.size())
694      return NULL;
695    return downloads[0];
696  }
697
698  // Wait for data
699  void WaitForData(DownloadItem* download, int size) {
700    DownloadUpdatedObserver data_observer(
701        download, base::Bind(&DataReceivedFilter, size));
702    data_observer.WaitForEvent();
703    ASSERT_EQ(size, download->GetReceivedBytes());
704    ASSERT_EQ(DownloadItem::IN_PROGRESS, download->GetState());
705  }
706
707  // Tell the test server to release a pending RST and confirm
708  // that the interrupt is received properly (for download resumption
709  // testing).
710  void ReleaseRSTAndConfirmInterruptForResume(DownloadItem* download) {
711    scoped_ptr<DownloadTestObserver> rst_observer(
712        CreateInterruptedWaiter(shell(), 1));
713    NavigateToURL(shell(), test_server()->GetURL("download-finish"));
714    rst_observer->WaitForFinished();
715    EXPECT_EQ(DownloadItem::INTERRUPTED, download->GetState());
716  }
717
718  // Confirm file status expected for the given location in a stream
719  // provided by the resume test server.
720  void ConfirmFileStatusForResume(
721      DownloadItem* download, bool file_exists,
722      int received_bytes, int total_bytes,
723      const base::FilePath& expected_filename) {
724    // expected_filename is only known if the file exists.
725    ASSERT_EQ(file_exists, !expected_filename.empty());
726    EXPECT_EQ(received_bytes, download->GetReceivedBytes());
727    EXPECT_EQ(total_bytes, download->GetTotalBytes());
728    EXPECT_EQ(expected_filename.value(),
729              download->GetFullPath().BaseName().value());
730    EXPECT_EQ(file_exists,
731              (!download->GetFullPath().empty() &&
732               base::PathExists(download->GetFullPath())));
733
734    if (file_exists) {
735      std::string file_contents;
736      EXPECT_TRUE(base::ReadFileToString(
737          download->GetFullPath(), &file_contents));
738
739      ASSERT_EQ(static_cast<size_t>(received_bytes), file_contents.size());
740      for (int i = 0; i < received_bytes; ++i) {
741        EXPECT_EQ(static_cast<char>((i * 2 + 15) % 256), file_contents[i])
742            << "File contents diverged at position " << i
743            << " for " << expected_filename.value();
744
745        if (static_cast<char>((i * 2 + 15) % 256) != file_contents[i])
746          return;
747      }
748    }
749  }
750
751 private:
752  static void EnsureNoPendingDownloadJobsOnIO(bool* result) {
753    if (URLRequestSlowDownloadJob::NumberOutstandingRequests())
754      *result = false;
755    BrowserThread::PostTask(
756        BrowserThread::UI, FROM_HERE, base::MessageLoop::QuitClosure());
757  }
758
759  // Location of the downloads directory for these tests
760  base::ScopedTempDir downloads_directory_;
761  scoped_ptr<TestShellDownloadManagerDelegate> test_delegate_;
762};
763
764IN_PROC_BROWSER_TEST_F(DownloadContentTest, DownloadCancelled) {
765  SetupEnsureNoPendingDownloads();
766
767  // Create a download, wait until it's started, and confirm
768  // we're in the expected state.
769  scoped_ptr<DownloadCreateObserver> observer(
770      CreateInProgressWaiter(shell(), 1));
771  NavigateToURL(shell(), GURL(URLRequestSlowDownloadJob::kUnknownSizeUrl));
772  observer->WaitForFinished();
773
774  std::vector<DownloadItem*> downloads;
775  DownloadManagerForShell(shell())->GetAllDownloads(&downloads);
776  ASSERT_EQ(1u, downloads.size());
777  ASSERT_EQ(DownloadItem::IN_PROGRESS, downloads[0]->GetState());
778
779  // Cancel the download and wait for download system quiesce.
780  downloads[0]->Cancel(true);
781  scoped_refptr<DownloadTestFlushObserver> flush_observer(
782      new DownloadTestFlushObserver(DownloadManagerForShell(shell())));
783  flush_observer->WaitForFlush();
784
785  // Get the important info from other threads and check it.
786  EXPECT_TRUE(EnsureNoPendingDownloads());
787}
788
789// Check that downloading multiple (in this case, 2) files does not result in
790// corrupted files.
791IN_PROC_BROWSER_TEST_F(DownloadContentTest, MultiDownload) {
792  SetupEnsureNoPendingDownloads();
793
794  // Create a download, wait until it's started, and confirm
795  // we're in the expected state.
796  scoped_ptr<DownloadCreateObserver> observer1(
797      CreateInProgressWaiter(shell(), 1));
798  NavigateToURL(shell(), GURL(URLRequestSlowDownloadJob::kUnknownSizeUrl));
799  observer1->WaitForFinished();
800
801  std::vector<DownloadItem*> downloads;
802  DownloadManagerForShell(shell())->GetAllDownloads(&downloads);
803  ASSERT_EQ(1u, downloads.size());
804  ASSERT_EQ(DownloadItem::IN_PROGRESS, downloads[0]->GetState());
805  DownloadItem* download1 = downloads[0];  // The only download.
806
807  // Start the second download and wait until it's done.
808  base::FilePath file(FILE_PATH_LITERAL("download-test.lib"));
809  GURL url(net::URLRequestMockHTTPJob::GetMockUrl(file));
810  // Download the file and wait.
811  NavigateToURLAndWaitForDownload(shell(), url, DownloadItem::COMPLETE);
812
813  // Should now have 2 items on the manager.
814  downloads.clear();
815  DownloadManagerForShell(shell())->GetAllDownloads(&downloads);
816  ASSERT_EQ(2u, downloads.size());
817  // We don't know the order of the downloads.
818  DownloadItem* download2 = downloads[(download1 == downloads[0]) ? 1 : 0];
819
820  ASSERT_EQ(DownloadItem::IN_PROGRESS, download1->GetState());
821  ASSERT_EQ(DownloadItem::COMPLETE, download2->GetState());
822
823  // Allow the first request to finish.
824  scoped_ptr<DownloadTestObserver> observer2(CreateWaiter(shell(), 1));
825  NavigateToURL(shell(), GURL(URLRequestSlowDownloadJob::kFinishDownloadUrl));
826  observer2->WaitForFinished();  // Wait for the third request.
827  EXPECT_EQ(1u, observer2->NumDownloadsSeenInState(DownloadItem::COMPLETE));
828
829  // Get the important info from other threads and check it.
830  EXPECT_TRUE(EnsureNoPendingDownloads());
831
832  // The |DownloadItem|s should now be done and have the final file names.
833  // Verify that the files have the expected data and size.
834  // |file1| should be full of '*'s, and |file2| should be the same as the
835  // source file.
836  base::FilePath file1(download1->GetTargetFilePath());
837  size_t file_size1 = URLRequestSlowDownloadJob::kFirstDownloadSize +
838                      URLRequestSlowDownloadJob::kSecondDownloadSize;
839  std::string expected_contents(file_size1, '*');
840  ASSERT_TRUE(VerifyFile(file1, expected_contents, file_size1));
841
842  base::FilePath file2(download2->GetTargetFilePath());
843  ASSERT_TRUE(base::ContentsEqual(
844      file2, GetTestFilePath("download", "download-test.lib")));
845}
846
847#if defined(ENABLE_PLUGINS)
848// Content served with a MIME type of application/octet-stream should be
849// downloaded even when a plugin can be found that handles the file type.
850IN_PROC_BROWSER_TEST_F(DownloadContentTest, DownloadOctetStream) {
851  const base::FilePath::CharType kTestFilePath[] =
852      FILE_PATH_LITERAL("octet-stream.abc");
853  const char kTestPluginName[] = "TestPlugin";
854  const char kTestMimeType[] = "application/x-test-mime-type";
855  const char kTestFileType[] = "abc";
856
857  WebPluginInfo plugin_info;
858  plugin_info.name = base::ASCIIToUTF16(kTestPluginName);
859  plugin_info.mime_types.push_back(
860      WebPluginMimeType(kTestMimeType, kTestFileType, ""));
861  PluginServiceImpl::GetInstance()->RegisterInternalPlugin(plugin_info, false);
862
863  // The following is served with a Content-Type of application/octet-stream.
864  GURL url(
865      net::URLRequestMockHTTPJob::GetMockUrl(base::FilePath(kTestFilePath)));
866  NavigateToURLAndWaitForDownload(shell(), url, DownloadItem::COMPLETE);
867}
868#endif
869
870// Try to cancel just before we release the download file, by delaying final
871// rename callback.
872IN_PROC_BROWSER_TEST_F(DownloadContentTest, CancelAtFinalRename) {
873  // Setup new factory.
874  DownloadFileWithDelayFactory* file_factory =
875      new DownloadFileWithDelayFactory();
876  DownloadManagerImpl* download_manager(DownloadManagerForShell(shell()));
877  download_manager->SetDownloadFileFactoryForTesting(
878      scoped_ptr<DownloadFileFactory>(file_factory).Pass());
879
880  // Create a download
881  base::FilePath file(FILE_PATH_LITERAL("download-test.lib"));
882  NavigateToURL(shell(), net::URLRequestMockHTTPJob::GetMockUrl(file));
883
884  // Wait until the first (intermediate file) rename and execute the callback.
885  file_factory->WaitForSomeCallback();
886  std::vector<base::Closure> callbacks;
887  file_factory->GetAllRenameCallbacks(&callbacks);
888  ASSERT_EQ(1u, callbacks.size());
889  callbacks[0].Run();
890  callbacks.clear();
891
892  // Wait until the second (final) rename callback is posted.
893  file_factory->WaitForSomeCallback();
894  file_factory->GetAllRenameCallbacks(&callbacks);
895  ASSERT_EQ(1u, callbacks.size());
896
897  // Cancel it.
898  std::vector<DownloadItem*> items;
899  download_manager->GetAllDownloads(&items);
900  ASSERT_EQ(1u, items.size());
901  items[0]->Cancel(true);
902  RunAllPendingInMessageLoop();
903
904  // Check state.
905  EXPECT_EQ(DownloadItem::CANCELLED, items[0]->GetState());
906
907  // Run final rename callback.
908  callbacks[0].Run();
909  callbacks.clear();
910
911  // Check state.
912  EXPECT_EQ(DownloadItem::CANCELLED, items[0]->GetState());
913}
914
915// Try to cancel just after we release the download file, by delaying
916// in ShouldOpenDownload.
917IN_PROC_BROWSER_TEST_F(DownloadContentTest, CancelAtRelease) {
918  DownloadManagerImpl* download_manager(DownloadManagerForShell(shell()));
919
920  // Mark delegate for delayed open.
921  GetDownloadManagerDelegate()->SetDelayedOpen(true);
922
923  // Setup new factory.
924  DownloadFileWithDelayFactory* file_factory =
925      new DownloadFileWithDelayFactory();
926  download_manager->SetDownloadFileFactoryForTesting(
927      scoped_ptr<DownloadFileFactory>(file_factory).Pass());
928
929  // Create a download
930  base::FilePath file(FILE_PATH_LITERAL("download-test.lib"));
931  NavigateToURL(shell(), net::URLRequestMockHTTPJob::GetMockUrl(file));
932
933  // Wait until the first (intermediate file) rename and execute the callback.
934  file_factory->WaitForSomeCallback();
935  std::vector<base::Closure> callbacks;
936  file_factory->GetAllRenameCallbacks(&callbacks);
937  ASSERT_EQ(1u, callbacks.size());
938  callbacks[0].Run();
939  callbacks.clear();
940
941  // Wait until the second (final) rename callback is posted.
942  file_factory->WaitForSomeCallback();
943  file_factory->GetAllRenameCallbacks(&callbacks);
944  ASSERT_EQ(1u, callbacks.size());
945
946  // Call it.
947  callbacks[0].Run();
948  callbacks.clear();
949
950  // Confirm download still IN_PROGRESS (internal state COMPLETING).
951  std::vector<DownloadItem*> items;
952  download_manager->GetAllDownloads(&items);
953  EXPECT_EQ(DownloadItem::IN_PROGRESS, items[0]->GetState());
954
955  // Cancel the download; confirm cancel fails.
956  ASSERT_EQ(1u, items.size());
957  items[0]->Cancel(true);
958  EXPECT_EQ(DownloadItem::IN_PROGRESS, items[0]->GetState());
959
960  // Need to complete open test.
961  std::vector<DownloadOpenDelayedCallback> delayed_callbacks;
962  GetDownloadManagerDelegate()->GetDelayedCallbacks(
963      &delayed_callbacks);
964  ASSERT_EQ(1u, delayed_callbacks.size());
965  delayed_callbacks[0].Run(true);
966
967  // *Now* the download should be complete.
968  EXPECT_EQ(DownloadItem::COMPLETE, items[0]->GetState());
969}
970
971// Try to shutdown with a download in progress to make sure shutdown path
972// works properly.
973IN_PROC_BROWSER_TEST_F(DownloadContentTest, ShutdownInProgress) {
974  // Create a download that won't complete.
975  scoped_ptr<DownloadCreateObserver> observer(
976      CreateInProgressWaiter(shell(), 1));
977  NavigateToURL(shell(), GURL(URLRequestSlowDownloadJob::kUnknownSizeUrl));
978  observer->WaitForFinished();
979
980  // Get the item.
981  std::vector<DownloadItem*> items;
982  DownloadManagerForShell(shell())->GetAllDownloads(&items);
983  ASSERT_EQ(1u, items.size());
984  EXPECT_EQ(DownloadItem::IN_PROGRESS, items[0]->GetState());
985
986  // Shutdown the download manager and make sure we get the right
987  // notifications in the right order.
988  StrictMock<MockDownloadItemObserver> item_observer;
989  items[0]->AddObserver(&item_observer);
990  MockDownloadManagerObserver manager_observer(
991      DownloadManagerForShell(shell()));
992  // Don't care about ModelChanged() events.
993  EXPECT_CALL(manager_observer, ModelChanged(_))
994      .WillRepeatedly(Return());
995  {
996    InSequence notifications;
997
998    EXPECT_CALL(manager_observer, MockManagerGoingDown(
999        DownloadManagerForShell(shell())))
1000        .WillOnce(Return());
1001    EXPECT_CALL(item_observer, OnDownloadUpdated(
1002        AllOf(items[0],
1003              Property(&DownloadItem::GetState, DownloadItem::CANCELLED))))
1004        .WillOnce(Return());
1005    EXPECT_CALL(item_observer, OnDownloadDestroyed(items[0]))
1006        .WillOnce(Return());
1007  }
1008
1009  // See http://crbug.com/324525.  If we have a refcount release/post task
1010  // race, the second post will stall the IO thread long enough so that we'll
1011  // lose the race and crash.  The first stall is just to give the UI thread
1012  // a chance to get the second stall onto the IO thread queue after the cancel
1013  // message created by Shutdown and before the notification callback
1014  // created by the IO thread in canceling the request.
1015  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
1016                          base::Bind(&base::PlatformThread::Sleep,
1017                                     base::TimeDelta::FromMilliseconds(25)));
1018  DownloadManagerForShell(shell())->Shutdown();
1019  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
1020                          base::Bind(&base::PlatformThread::Sleep,
1021                                     base::TimeDelta::FromMilliseconds(25)));
1022  items.clear();
1023}
1024
1025// Try to shutdown just after we release the download file, by delaying
1026// release.
1027IN_PROC_BROWSER_TEST_F(DownloadContentTest, ShutdownAtRelease) {
1028  DownloadManagerImpl* download_manager(DownloadManagerForShell(shell()));
1029
1030  // Mark delegate for delayed open.
1031  GetDownloadManagerDelegate()->SetDelayedOpen(true);
1032
1033  // Setup new factory.
1034  DownloadFileWithDelayFactory* file_factory =
1035      new DownloadFileWithDelayFactory();
1036  download_manager->SetDownloadFileFactoryForTesting(
1037      scoped_ptr<DownloadFileFactory>(file_factory).Pass());
1038
1039  // Create a download
1040  base::FilePath file(FILE_PATH_LITERAL("download-test.lib"));
1041  NavigateToURL(shell(), net::URLRequestMockHTTPJob::GetMockUrl(file));
1042
1043  // Wait until the first (intermediate file) rename and execute the callback.
1044  file_factory->WaitForSomeCallback();
1045  std::vector<base::Closure> callbacks;
1046  file_factory->GetAllRenameCallbacks(&callbacks);
1047  ASSERT_EQ(1u, callbacks.size());
1048  callbacks[0].Run();
1049  callbacks.clear();
1050
1051  // Wait until the second (final) rename callback is posted.
1052  file_factory->WaitForSomeCallback();
1053  file_factory->GetAllRenameCallbacks(&callbacks);
1054  ASSERT_EQ(1u, callbacks.size());
1055
1056  // Call it.
1057  callbacks[0].Run();
1058  callbacks.clear();
1059
1060  // Confirm download isn't complete yet.
1061  std::vector<DownloadItem*> items;
1062  DownloadManagerForShell(shell())->GetAllDownloads(&items);
1063  EXPECT_EQ(DownloadItem::IN_PROGRESS, items[0]->GetState());
1064
1065  // Cancel the download; confirm cancel fails anyway.
1066  ASSERT_EQ(1u, items.size());
1067  items[0]->Cancel(true);
1068  EXPECT_EQ(DownloadItem::IN_PROGRESS, items[0]->GetState());
1069  RunAllPendingInMessageLoop();
1070  EXPECT_EQ(DownloadItem::IN_PROGRESS, items[0]->GetState());
1071
1072  MockDownloadItemObserver observer;
1073  items[0]->AddObserver(&observer);
1074  EXPECT_CALL(observer, OnDownloadDestroyed(items[0]));
1075
1076  // Shutdown the download manager.  Mostly this is confirming a lack of
1077  // crashes.
1078  DownloadManagerForShell(shell())->Shutdown();
1079}
1080
1081IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeInterruptedDownload) {
1082  base::CommandLine::ForCurrentProcess()->AppendSwitch(
1083      switches::kEnableDownloadResumption);
1084  ASSERT_TRUE(test_server()->Start());
1085
1086  GURL url = test_server()->GetURL(
1087      base::StringPrintf("rangereset?size=%d&rst_boundary=%d",
1088                   GetSafeBufferChunk() * 3, GetSafeBufferChunk()));
1089
1090  MockDownloadManagerObserver dm_observer(DownloadManagerForShell(shell()));
1091  EXPECT_CALL(dm_observer, OnDownloadCreated(_,_)).Times(1);
1092
1093  DownloadItem* download(StartDownloadAndReturnItem(url));
1094  WaitForData(download, GetSafeBufferChunk());
1095  ::testing::Mock::VerifyAndClearExpectations(&dm_observer);
1096
1097  // Confirm resumption while in progress doesn't do anything.
1098  download->Resume();
1099  ASSERT_EQ(GetSafeBufferChunk(), download->GetReceivedBytes());
1100  ASSERT_EQ(DownloadItem::IN_PROGRESS, download->GetState());
1101
1102  // Tell the server to send the RST and confirm the interrupt happens.
1103  ReleaseRSTAndConfirmInterruptForResume(download);
1104  ConfirmFileStatusForResume(
1105      download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3,
1106      base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload")));
1107
1108  // Resume, confirming received bytes on resumption is correct.
1109  // Make sure no creation calls are included.
1110  EXPECT_CALL(dm_observer, OnDownloadCreated(_,_)).Times(0);
1111  int initial_size = 0;
1112  DownloadUpdatedObserver initial_size_observer(
1113      download, base::Bind(&InitialSizeFilter, &initial_size));
1114  download->Resume();
1115  initial_size_observer.WaitForEvent();
1116  EXPECT_EQ(GetSafeBufferChunk(), initial_size);
1117  ::testing::Mock::VerifyAndClearExpectations(&dm_observer);
1118
1119  // and wait for expected data.
1120  WaitForData(download, GetSafeBufferChunk() * 2);
1121
1122  // Tell the server to send the RST and confirm the interrupt happens.
1123  ReleaseRSTAndConfirmInterruptForResume(download);
1124  ConfirmFileStatusForResume(
1125      download, true, GetSafeBufferChunk() * 2, GetSafeBufferChunk() * 3,
1126      base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload")));
1127
1128  // Resume and wait for completion.
1129  DownloadUpdatedObserver completion_observer(
1130      download, base::Bind(DownloadCompleteFilter));
1131  download->Resume();
1132  completion_observer.WaitForEvent();
1133
1134  ConfirmFileStatusForResume(
1135      download, true, GetSafeBufferChunk() * 3, GetSafeBufferChunk() * 3,
1136      base::FilePath(FILE_PATH_LITERAL("rangereset")));
1137
1138  // Confirm resumption while complete doesn't do anything.
1139  download->Resume();
1140  ASSERT_EQ(GetSafeBufferChunk() * 3, download->GetReceivedBytes());
1141  ASSERT_EQ(DownloadItem::COMPLETE, download->GetState());
1142  RunAllPendingInMessageLoop();
1143  ASSERT_EQ(GetSafeBufferChunk() * 3, download->GetReceivedBytes());
1144  ASSERT_EQ(DownloadItem::COMPLETE, download->GetState());
1145}
1146
1147// Confirm restart fallback happens if a range request is bounced.
1148IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeInterruptedDownloadNoRange) {
1149  base::CommandLine::ForCurrentProcess()->AppendSwitch(
1150      switches::kEnableDownloadResumption);
1151  ASSERT_TRUE(test_server()->Start());
1152
1153  // Auto-restart if server doesn't handle ranges.
1154  GURL url = test_server()->GetURL(
1155      base::StringPrintf(
1156          // First download hits an RST, rest don't, no ranges.
1157          "rangereset?size=%d&rst_boundary=%d&"
1158          "token=NoRange&rst_limit=1&bounce_range",
1159          GetSafeBufferChunk() * 3, GetSafeBufferChunk()));
1160
1161  // Start the download and wait for first data chunk.
1162  DownloadItem* download(StartDownloadAndReturnItem(url));
1163  WaitForData(download, GetSafeBufferChunk());
1164
1165  RecordingDownloadObserver recorder(download);
1166
1167  ReleaseRSTAndConfirmInterruptForResume(download);
1168  ConfirmFileStatusForResume(
1169      download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3,
1170      base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload")));
1171
1172  DownloadUpdatedObserver completion_observer(
1173      download, base::Bind(DownloadCompleteFilter));
1174  download->Resume();
1175  completion_observer.WaitForEvent();
1176
1177  ConfirmFileStatusForResume(
1178      download, true, GetSafeBufferChunk() * 3, GetSafeBufferChunk() * 3,
1179      base::FilePath(FILE_PATH_LITERAL("rangereset")));
1180
1181  static const RecordingDownloadObserver::RecordStruct expected_record[] = {
1182    // Result of RST
1183    {DownloadItem::INTERRUPTED, GetSafeBufferChunk()},
1184    // Starting continuation
1185    {DownloadItem::IN_PROGRESS, GetSafeBufferChunk()},
1186    // Notification of receiving whole file.
1187    {DownloadItem::IN_PROGRESS, 0},
1188    // Completion.
1189    {DownloadItem::COMPLETE, GetSafeBufferChunk() * 3},
1190  };
1191
1192  recorder.CompareToExpectedRecord(expected_record, arraysize(expected_record));
1193}
1194
1195// Confirm restart fallback happens if a precondition is failed.
1196IN_PROC_BROWSER_TEST_F(DownloadContentTest,
1197                       ResumeInterruptedDownloadBadPrecondition) {
1198  base::CommandLine::ForCurrentProcess()->AppendSwitch(
1199      switches::kEnableDownloadResumption);
1200  ASSERT_TRUE(test_server()->Start());
1201
1202  GURL url = test_server()->GetURL(base::StringPrintf(
1203      // First download hits an RST, rest don't, precondition fail.
1204      "rangereset?size=%d&rst_boundary=%d&"
1205      "token=BadPrecondition&rst_limit=1&fail_precondition=2",
1206      GetSafeBufferChunk() * 3,
1207      GetSafeBufferChunk()));
1208
1209  // Start the download and wait for first data chunk.
1210  DownloadItem* download(StartDownloadAndReturnItem(url));
1211  WaitForData(download, GetSafeBufferChunk());
1212
1213  RecordingDownloadObserver recorder(download);
1214
1215  ReleaseRSTAndConfirmInterruptForResume(download);
1216  ConfirmFileStatusForResume(
1217      download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3,
1218      base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload")));
1219  EXPECT_EQ("BadPrecondition2", download->GetETag());
1220
1221  DownloadUpdatedObserver completion_observer(
1222      download, base::Bind(DownloadCompleteFilter));
1223  download->Resume();
1224  completion_observer.WaitForEvent();
1225
1226  ConfirmFileStatusForResume(
1227      download, true, GetSafeBufferChunk() * 3, GetSafeBufferChunk() * 3,
1228      base::FilePath(FILE_PATH_LITERAL("rangereset")));
1229  EXPECT_EQ("BadPrecondition0", download->GetETag());
1230
1231  static const RecordingDownloadObserver::RecordStruct expected_record[] = {
1232    // Result of RST
1233    {DownloadItem::INTERRUPTED, GetSafeBufferChunk()},
1234    // Starting continuation
1235    {DownloadItem::IN_PROGRESS, GetSafeBufferChunk()},
1236    // Server precondition fail.
1237    {DownloadItem::INTERRUPTED, 0},
1238    // Notification of successful restart.
1239    {DownloadItem::IN_PROGRESS, 0},
1240    // Completion.
1241    {DownloadItem::COMPLETE, GetSafeBufferChunk() * 3},
1242  };
1243
1244  recorder.CompareToExpectedRecord(expected_record, arraysize(expected_record));
1245}
1246
1247// Confirm we don't try to resume if we don't have a verifier.
1248IN_PROC_BROWSER_TEST_F(DownloadContentTest,
1249                       ResumeInterruptedDownloadNoVerifiers) {
1250  base::CommandLine::ForCurrentProcess()->AppendSwitch(
1251      switches::kEnableDownloadResumption);
1252  ASSERT_TRUE(test_server()->Start());
1253
1254  GURL url = test_server()->GetURL(
1255      base::StringPrintf(
1256          // First download hits an RST, rest don't, no verifiers.
1257          "rangereset?size=%d&rst_boundary=%d&"
1258          "token=NoRange&rst_limit=1&no_verifiers",
1259          GetSafeBufferChunk() * 3, GetSafeBufferChunk()));
1260
1261  // Start the download and wait for first data chunk.
1262  DownloadItem* download(StartDownloadAndReturnItem(url));
1263  WaitForData(download, GetSafeBufferChunk());
1264
1265  RecordingDownloadObserver recorder(download);
1266
1267  ReleaseRSTAndConfirmInterruptForResume(download);
1268  ConfirmFileStatusForResume(
1269      download, false, GetSafeBufferChunk(), GetSafeBufferChunk() * 3,
1270      base::FilePath());
1271
1272  DownloadUpdatedObserver completion_observer(
1273      download, base::Bind(DownloadCompleteFilter));
1274  download->Resume();
1275  completion_observer.WaitForEvent();
1276
1277  ConfirmFileStatusForResume(
1278      download, true, GetSafeBufferChunk() * 3, GetSafeBufferChunk() * 3,
1279      base::FilePath(FILE_PATH_LITERAL("rangereset")));
1280
1281  static const RecordingDownloadObserver::RecordStruct expected_record[] = {
1282    // Result of RST
1283    {DownloadItem::INTERRUPTED, GetSafeBufferChunk()},
1284    // Restart for lack of verifiers
1285    {DownloadItem::IN_PROGRESS, 0},
1286    // Completion.
1287    {DownloadItem::COMPLETE, GetSafeBufferChunk() * 3},
1288  };
1289
1290  recorder.CompareToExpectedRecord(expected_record, arraysize(expected_record));
1291}
1292
1293IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeWithDeletedFile) {
1294  base::CommandLine::ForCurrentProcess()->AppendSwitch(
1295      switches::kEnableDownloadResumption);
1296  ASSERT_TRUE(test_server()->Start());
1297
1298  GURL url = test_server()->GetURL(
1299      base::StringPrintf(
1300          // First download hits an RST, rest don't
1301          "rangereset?size=%d&rst_boundary=%d&"
1302          "token=NoRange&rst_limit=1",
1303          GetSafeBufferChunk() * 3, GetSafeBufferChunk()));
1304
1305  // Start the download and wait for first data chunk.
1306  DownloadItem* download(StartDownloadAndReturnItem(url));
1307  WaitForData(download, GetSafeBufferChunk());
1308
1309  RecordingDownloadObserver recorder(download);
1310
1311  ReleaseRSTAndConfirmInterruptForResume(download);
1312  ConfirmFileStatusForResume(
1313      download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3,
1314      base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload")));
1315
1316  // Delete the intermediate file.
1317  base::DeleteFile(download->GetFullPath(), false);
1318
1319  DownloadUpdatedObserver completion_observer(
1320      download, base::Bind(DownloadCompleteFilter));
1321  download->Resume();
1322  completion_observer.WaitForEvent();
1323
1324  ConfirmFileStatusForResume(
1325      download, true, GetSafeBufferChunk() * 3, GetSafeBufferChunk() * 3,
1326      base::FilePath(FILE_PATH_LITERAL("rangereset")));
1327
1328  static const RecordingDownloadObserver::RecordStruct expected_record[] = {
1329    // Result of RST
1330    {DownloadItem::INTERRUPTED, GetSafeBufferChunk()},
1331    // Starting continuation
1332    {DownloadItem::IN_PROGRESS, GetSafeBufferChunk()},
1333    // Error because file isn't there.
1334    {DownloadItem::INTERRUPTED, 0},
1335    // Restart.
1336    {DownloadItem::IN_PROGRESS, 0},
1337    // Completion.
1338    {DownloadItem::COMPLETE, GetSafeBufferChunk() * 3},
1339  };
1340
1341  recorder.CompareToExpectedRecord(expected_record, arraysize(expected_record));
1342}
1343
1344IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeWithFileInitError) {
1345  base::CommandLine::ForCurrentProcess()->AppendSwitch(
1346      switches::kEnableDownloadResumption);
1347  base::FilePath file(FILE_PATH_LITERAL("download-test.lib"));
1348  GURL url(net::URLRequestMockHTTPJob::GetMockUrl(file));
1349
1350  // Setup the error injector.
1351  scoped_refptr<TestFileErrorInjector> injector(
1352      TestFileErrorInjector::Create(DownloadManagerForShell(shell())));
1353
1354  TestFileErrorInjector::FileErrorInfo err = {
1355    url.spec(),
1356    TestFileErrorInjector::FILE_OPERATION_INITIALIZE,
1357    0,
1358    DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE
1359  };
1360  injector->AddError(err);
1361  injector->InjectErrors();
1362
1363  // Start and watch for interrupt.
1364  scoped_ptr<DownloadTestObserver> int_observer(
1365      CreateInterruptedWaiter(shell(), 1));
1366  DownloadItem* download(StartDownloadAndReturnItem(url));
1367  int_observer->WaitForFinished();
1368  ASSERT_EQ(DownloadItem::INTERRUPTED, download->GetState());
1369  EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE,
1370            download->GetLastReason());
1371  EXPECT_EQ(0, download->GetReceivedBytes());
1372  EXPECT_TRUE(download->GetFullPath().empty());
1373  EXPECT_TRUE(download->GetTargetFilePath().empty());
1374
1375  // We need to make sure that any cross-thread downloads communication has
1376  // quiesced before clearing and injecting the new errors, as the
1377  // InjectErrors() routine alters the currently in use download file
1378  // factory, which is a file thread object.
1379  RunAllPendingInMessageLoop(BrowserThread::FILE);
1380  RunAllPendingInMessageLoop();
1381
1382  // Clear the old errors list.
1383  injector->ClearErrors();
1384  injector->InjectErrors();
1385
1386  // Resume and watch completion.
1387  DownloadUpdatedObserver completion_observer(
1388      download, base::Bind(DownloadCompleteFilter));
1389  download->Resume();
1390  completion_observer.WaitForEvent();
1391  EXPECT_EQ(download->GetState(), DownloadItem::COMPLETE);
1392}
1393
1394IN_PROC_BROWSER_TEST_F(DownloadContentTest,
1395                       ResumeWithFileIntermediateRenameError) {
1396  base::CommandLine::ForCurrentProcess()->AppendSwitch(
1397      switches::kEnableDownloadResumption);
1398  base::FilePath file(FILE_PATH_LITERAL("download-test.lib"));
1399  GURL url(net::URLRequestMockHTTPJob::GetMockUrl(file));
1400
1401  // Setup the error injector.
1402  scoped_refptr<TestFileErrorInjector> injector(
1403      TestFileErrorInjector::Create(DownloadManagerForShell(shell())));
1404
1405  TestFileErrorInjector::FileErrorInfo err = {
1406    url.spec(),
1407    TestFileErrorInjector::FILE_OPERATION_RENAME_UNIQUIFY,
1408    0,
1409    DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE
1410  };
1411  injector->AddError(err);
1412  injector->InjectErrors();
1413
1414  // Start and watch for interrupt.
1415  scoped_ptr<DownloadTestObserver> int_observer(
1416      CreateInterruptedWaiter(shell(), 1));
1417  DownloadItem* download(StartDownloadAndReturnItem(url));
1418  int_observer->WaitForFinished();
1419  ASSERT_EQ(DownloadItem::INTERRUPTED, download->GetState());
1420  EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE,
1421            download->GetLastReason());
1422  EXPECT_TRUE(download->GetFullPath().empty());
1423  // Target path will have been set after file name determination. GetFullPath()
1424  // being empty is sufficient to signal that filename determination needs to be
1425  // redone.
1426  EXPECT_FALSE(download->GetTargetFilePath().empty());
1427
1428  // We need to make sure that any cross-thread downloads communication has
1429  // quiesced before clearing and injecting the new errors, as the
1430  // InjectErrors() routine alters the currently in use download file
1431  // factory, which is a file thread object.
1432  RunAllPendingInMessageLoop(BrowserThread::FILE);
1433  RunAllPendingInMessageLoop();
1434
1435  // Clear the old errors list.
1436  injector->ClearErrors();
1437  injector->InjectErrors();
1438
1439  // Resume and watch completion.
1440  DownloadUpdatedObserver completion_observer(
1441      download, base::Bind(DownloadCompleteFilter));
1442  download->Resume();
1443  completion_observer.WaitForEvent();
1444  EXPECT_EQ(download->GetState(), DownloadItem::COMPLETE);
1445}
1446
1447IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeWithFileFinalRenameError) {
1448  base::CommandLine::ForCurrentProcess()->AppendSwitch(
1449      switches::kEnableDownloadResumption);
1450  base::FilePath file(FILE_PATH_LITERAL("download-test.lib"));
1451  GURL url(net::URLRequestMockHTTPJob::GetMockUrl(file));
1452
1453  // Setup the error injector.
1454  scoped_refptr<TestFileErrorInjector> injector(
1455      TestFileErrorInjector::Create(DownloadManagerForShell(shell())));
1456
1457  DownloadManagerForShell(shell())->RemoveAllDownloads();
1458  TestFileErrorInjector::FileErrorInfo err = {
1459    url.spec(),
1460    TestFileErrorInjector::FILE_OPERATION_RENAME_ANNOTATE,
1461    0,
1462    DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE
1463  };
1464  injector->AddError(err);
1465  injector->InjectErrors();
1466
1467  // Start and watch for interrupt.
1468  scoped_ptr<DownloadTestObserver> int_observer(
1469      CreateInterruptedWaiter(shell(), 1));
1470  DownloadItem* download(StartDownloadAndReturnItem(url));
1471  int_observer->WaitForFinished();
1472  ASSERT_EQ(DownloadItem::INTERRUPTED, download->GetState());
1473  EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE,
1474            download->GetLastReason());
1475  EXPECT_TRUE(download->GetFullPath().empty());
1476  // Target path should still be intact.
1477  EXPECT_FALSE(download->GetTargetFilePath().empty());
1478
1479  // We need to make sure that any cross-thread downloads communication has
1480  // quiesced before clearing and injecting the new errors, as the
1481  // InjectErrors() routine alters the currently in use download file
1482  // factory, which is a file thread object.
1483  RunAllPendingInMessageLoop(BrowserThread::FILE);
1484  RunAllPendingInMessageLoop();
1485
1486  // Clear the old errors list.
1487  injector->ClearErrors();
1488  injector->InjectErrors();
1489
1490  // Resume and watch completion.
1491  DownloadUpdatedObserver completion_observer(
1492      download, base::Bind(DownloadCompleteFilter));
1493  download->Resume();
1494  completion_observer.WaitForEvent();
1495  EXPECT_EQ(download->GetState(), DownloadItem::COMPLETE);
1496}
1497
1498// An interrupted download should remove the intermediate file when it is
1499// cancelled.
1500IN_PROC_BROWSER_TEST_F(DownloadContentTest, CancelInterruptedDownload) {
1501  base::CommandLine::ForCurrentProcess()->AppendSwitch(
1502      switches::kEnableDownloadResumption);
1503  ASSERT_TRUE(test_server()->Start());
1504
1505  GURL url1 = test_server()->GetURL(
1506      base::StringPrintf("rangereset?size=%d&rst_boundary=%d",
1507                         GetSafeBufferChunk() * 3, GetSafeBufferChunk()));
1508
1509  DownloadItem* download(StartDownloadAndReturnItem(url1));
1510  WaitForData(download, GetSafeBufferChunk());
1511
1512  ReleaseRSTAndConfirmInterruptForResume(download);
1513  ConfirmFileStatusForResume(
1514      download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3,
1515      base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload")));
1516
1517  base::FilePath intermediate_path(download->GetFullPath());
1518  ASSERT_FALSE(intermediate_path.empty());
1519  EXPECT_TRUE(base::PathExists(intermediate_path));
1520
1521  download->Cancel(true /* user_cancel */);
1522  RunAllPendingInMessageLoop(BrowserThread::FILE);
1523  RunAllPendingInMessageLoop();
1524
1525  // The intermediate file should now be gone.
1526  EXPECT_FALSE(base::PathExists(intermediate_path));
1527  EXPECT_TRUE(download->GetFullPath().empty());
1528}
1529
1530IN_PROC_BROWSER_TEST_F(DownloadContentTest, RemoveDownload) {
1531  base::CommandLine::ForCurrentProcess()->AppendSwitch(
1532      switches::kEnableDownloadResumption);
1533  ASSERT_TRUE(test_server()->Start());
1534
1535  // An interrupted download should remove the intermediate file when it is
1536  // removed.
1537  {
1538    GURL url1 = test_server()->GetURL(
1539        base::StringPrintf("rangereset?size=%d&rst_boundary=%d",
1540                           GetSafeBufferChunk() * 3, GetSafeBufferChunk()));
1541
1542    DownloadItem* download(StartDownloadAndReturnItem(url1));
1543    WaitForData(download, GetSafeBufferChunk());
1544    ReleaseRSTAndConfirmInterruptForResume(download);
1545    ConfirmFileStatusForResume(
1546        download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3,
1547        base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload")));
1548
1549    base::FilePath intermediate_path(download->GetFullPath());
1550    ASSERT_FALSE(intermediate_path.empty());
1551    EXPECT_TRUE(base::PathExists(intermediate_path));
1552
1553    download->Remove();
1554    RunAllPendingInMessageLoop(BrowserThread::FILE);
1555    RunAllPendingInMessageLoop();
1556
1557    // The intermediate file should now be gone.
1558    EXPECT_FALSE(base::PathExists(intermediate_path));
1559  }
1560
1561  // A completed download shouldn't delete the downloaded file when it is
1562  // removed.
1563  {
1564    // Start the second download and wait until it's done.
1565    base::FilePath file2(FILE_PATH_LITERAL("download-test.lib"));
1566    GURL url2(net::URLRequestMockHTTPJob::GetMockUrl(file2));
1567    scoped_ptr<DownloadTestObserver> completion_observer(
1568        CreateWaiter(shell(), 1));
1569    DownloadItem* download(StartDownloadAndReturnItem(url2));
1570    completion_observer->WaitForFinished();
1571
1572    // The target path should exist.
1573    base::FilePath target_path(download->GetTargetFilePath());
1574    EXPECT_TRUE(base::PathExists(target_path));
1575    download->Remove();
1576    RunAllPendingInMessageLoop(BrowserThread::FILE);
1577    RunAllPendingInMessageLoop();
1578
1579    // The file should still exist.
1580    EXPECT_TRUE(base::PathExists(target_path));
1581  }
1582}
1583
1584IN_PROC_BROWSER_TEST_F(DownloadContentTest, RemoveResumingDownload) {
1585  SetupEnsureNoPendingDownloads();
1586  base::CommandLine::ForCurrentProcess()->AppendSwitch(
1587      switches::kEnableDownloadResumption);
1588  ASSERT_TRUE(test_server()->Start());
1589
1590  GURL url = test_server()->GetURL(
1591      base::StringPrintf("rangereset?size=%d&rst_boundary=%d",
1592                         GetSafeBufferChunk() * 3, GetSafeBufferChunk()));
1593
1594  MockDownloadManagerObserver dm_observer(DownloadManagerForShell(shell()));
1595  EXPECT_CALL(dm_observer, OnDownloadCreated(_,_)).Times(1);
1596
1597  DownloadItem* download(StartDownloadAndReturnItem(url));
1598  WaitForData(download, GetSafeBufferChunk());
1599  ::testing::Mock::VerifyAndClearExpectations(&dm_observer);
1600
1601  // Tell the server to send the RST and confirm the interrupt happens.
1602  ReleaseRSTAndConfirmInterruptForResume(download);
1603  ConfirmFileStatusForResume(
1604      download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3,
1605      base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload")));
1606
1607  base::FilePath intermediate_path(download->GetFullPath());
1608  ASSERT_FALSE(intermediate_path.empty());
1609  EXPECT_TRUE(base::PathExists(intermediate_path));
1610
1611  // Resume and remove download. We expect only a single OnDownloadCreated()
1612  // call, and that's for the second download created below.
1613  EXPECT_CALL(dm_observer, OnDownloadCreated(_,_)).Times(1);
1614  download->Resume();
1615  download->Remove();
1616
1617  // The intermediate file should now be gone.
1618  RunAllPendingInMessageLoop(BrowserThread::FILE);
1619  RunAllPendingInMessageLoop();
1620  EXPECT_FALSE(base::PathExists(intermediate_path));
1621
1622  // Start the second download and wait until it's done. The test server is
1623  // single threaded. The response to this download request should follow the
1624  // response to the previous resumption request.
1625  GURL url2(test_server()->GetURL("rangereset?size=100&rst_limit=0&token=x"));
1626  NavigateToURLAndWaitForDownload(shell(), url2, DownloadItem::COMPLETE);
1627
1628  EXPECT_TRUE(EnsureNoPendingDownloads());
1629}
1630
1631IN_PROC_BROWSER_TEST_F(DownloadContentTest, CancelResumingDownload) {
1632  SetupEnsureNoPendingDownloads();
1633  base::CommandLine::ForCurrentProcess()->AppendSwitch(
1634      switches::kEnableDownloadResumption);
1635  ASSERT_TRUE(test_server()->Start());
1636
1637  GURL url = test_server()->GetURL(
1638      base::StringPrintf("rangereset?size=%d&rst_boundary=%d",
1639                         GetSafeBufferChunk() * 3, GetSafeBufferChunk()));
1640
1641  MockDownloadManagerObserver dm_observer(DownloadManagerForShell(shell()));
1642  EXPECT_CALL(dm_observer, OnDownloadCreated(_,_)).Times(1);
1643
1644  DownloadItem* download(StartDownloadAndReturnItem(url));
1645  WaitForData(download, GetSafeBufferChunk());
1646  ::testing::Mock::VerifyAndClearExpectations(&dm_observer);
1647
1648  // Tell the server to send the RST and confirm the interrupt happens.
1649  ReleaseRSTAndConfirmInterruptForResume(download);
1650  ConfirmFileStatusForResume(
1651      download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3,
1652      base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload")));
1653
1654  base::FilePath intermediate_path(download->GetFullPath());
1655  ASSERT_FALSE(intermediate_path.empty());
1656  EXPECT_TRUE(base::PathExists(intermediate_path));
1657
1658  // Resume and cancel download. We expect only a single OnDownloadCreated()
1659  // call, and that's for the second download created below.
1660  EXPECT_CALL(dm_observer, OnDownloadCreated(_,_)).Times(1);
1661  download->Resume();
1662  download->Cancel(true);
1663
1664  // The intermediate file should now be gone.
1665  RunAllPendingInMessageLoop(BrowserThread::FILE);
1666  RunAllPendingInMessageLoop();
1667  EXPECT_FALSE(base::PathExists(intermediate_path));
1668  EXPECT_TRUE(download->GetFullPath().empty());
1669
1670  // Start the second download and wait until it's done. The test server is
1671  // single threaded. The response to this download request should follow the
1672  // response to the previous resumption request.
1673  GURL url2(test_server()->GetURL("rangereset?size=100&rst_limit=0&token=x"));
1674  NavigateToURLAndWaitForDownload(shell(), url2, DownloadItem::COMPLETE);
1675
1676  EXPECT_TRUE(EnsureNoPendingDownloads());
1677}
1678
1679// Check that the cookie policy is correctly updated when downloading a file
1680// that redirects cross origin.
1681IN_PROC_BROWSER_TEST_F(DownloadContentTest, CookiePolicy) {
1682  ASSERT_TRUE(test_server()->Start());
1683  net::HostPortPair host_port = test_server()->host_port_pair();
1684  DCHECK_EQ(host_port.host(), std::string("127.0.0.1"));
1685
1686  // Block third-party cookies.
1687  ShellNetworkDelegate::SetAcceptAllCookies(false);
1688
1689  // |url| redirects to a different origin |download| which tries to set a
1690  // cookie.
1691  std::string download(base::StringPrintf(
1692      "http://localhost:%d/set-cookie?A=B", host_port.port()));
1693  GURL url(test_server()->GetURL("server-redirect?" + download));
1694
1695  // Download the file.
1696  SetupEnsureNoPendingDownloads();
1697  scoped_ptr<DownloadUrlParameters> dl_params(
1698      DownloadUrlParameters::FromWebContents(shell()->web_contents(), url));
1699  scoped_ptr<DownloadTestObserver> observer(CreateWaiter(shell(), 1));
1700  DownloadManagerForShell(shell())->DownloadUrl(dl_params.Pass());
1701  observer->WaitForFinished();
1702
1703  // Get the important info from other threads and check it.
1704  EXPECT_TRUE(EnsureNoPendingDownloads());
1705
1706  std::vector<DownloadItem*> downloads;
1707  DownloadManagerForShell(shell())->GetAllDownloads(&downloads);
1708  ASSERT_EQ(1u, downloads.size());
1709  ASSERT_EQ(DownloadItem::COMPLETE, downloads[0]->GetState());
1710
1711  // Check that the cookies were correctly set.
1712  EXPECT_EQ("A=B",
1713            content::GetCookies(shell()->web_contents()->GetBrowserContext(),
1714                                GURL(download)));
1715}
1716
1717// A filename suggestion specified via a @download attribute should not be
1718// effective if the final download URL is in another origin from the original
1719// download URL.
1720IN_PROC_BROWSER_TEST_F(DownloadContentTest,
1721                       DownloadAttributeCrossOriginRedirect) {
1722  EmbeddedTestServer origin_one;
1723  EmbeddedTestServer origin_two;
1724  ASSERT_TRUE(origin_one.InitializeAndWaitUntilReady());
1725  ASSERT_TRUE(origin_two.InitializeAndWaitUntilReady());
1726
1727  // The download-attribute.html page contains an anchor element whose href is
1728  // set to the value of the query parameter (specified as |target| in the URL
1729  // below). The suggested filename for the anchor is 'suggested-filename'. When
1730  // the page is loaded, a script simulates a click on the anchor, triggering a
1731  // download of the target URL.
1732  //
1733  // We construct two test servers; origin_one and origin_two. Once started, the
1734  // server URLs will differ by the port number. Therefore they will be in
1735  // different origins.
1736  GURL download_url = origin_one.GetURL("/ping");
1737  GURL referrer_url = origin_one.GetURL(
1738      std::string("/download-attribute.html?target=") + download_url.spec());
1739
1740  // <origin_one>/download-attribute.html initiates a download of
1741  // <origin_one>/ping, which redirects to <origin_two>/download.
1742  origin_one.ServeFilesFromDirectory(GetTestFilePath("download", ""));
1743  origin_one.RegisterRequestHandler(
1744      CreateRedirectHandler("/ping", origin_two.GetURL("/download")));
1745  origin_two.RegisterRequestHandler(CreateBasicResponseHandler(
1746      "/download", "application/octet-stream", "Hello"));
1747
1748  NavigateToURLAndWaitForDownload(
1749      shell(), referrer_url, DownloadItem::COMPLETE);
1750
1751  std::vector<DownloadItem*> downloads;
1752  DownloadManagerForShell(shell())->GetAllDownloads(&downloads);
1753  ASSERT_EQ(1u, downloads.size());
1754
1755  EXPECT_EQ(FILE_PATH_LITERAL("download"),
1756            downloads[0]->GetTargetFilePath().BaseName().value());
1757  ASSERT_TRUE(origin_one.ShutdownAndWaitUntilComplete());
1758  ASSERT_TRUE(origin_two.ShutdownAndWaitUntilComplete());
1759}
1760
1761// A filename suggestion specified via a @download attribute should be effective
1762// if the final download URL is in the same origin as the initial download URL.
1763// Test that this holds even if there are cross origin redirects in the middle
1764// of the redirect chain.
1765IN_PROC_BROWSER_TEST_F(DownloadContentTest,
1766                       DownloadAttributeSameOriginRedirect) {
1767  EmbeddedTestServer origin_one;
1768  EmbeddedTestServer origin_two;
1769  ASSERT_TRUE(origin_one.InitializeAndWaitUntilReady());
1770  ASSERT_TRUE(origin_two.InitializeAndWaitUntilReady());
1771
1772  // The download-attribute.html page contains an anchor element whose href is
1773  // set to the value of the query parameter (specified as |target| in the URL
1774  // below). The suggested filename for the anchor is 'suggested-filename'. When
1775  // the page is loaded, a script simulates a click on the anchor, triggering a
1776  // download of the target URL.
1777  //
1778  // We construct two test servers; origin_one and origin_two. Once started, the
1779  // server URLs will differ by the port number. Therefore they will be in
1780  // different origins.
1781  GURL download_url = origin_one.GetURL("/ping");
1782  GURL referrer_url = origin_one.GetURL(
1783      std::string("/download-attribute.html?target=") + download_url.spec());
1784  origin_one.ServeFilesFromDirectory(GetTestFilePath("download", ""));
1785
1786  // <origin_one>/download-attribute.html initiates a download of
1787  // <origin_one>/ping, which redirects to <origin_two>/pong, and then finally
1788  // to <origin_one>/download.
1789  origin_one.RegisterRequestHandler(
1790      CreateRedirectHandler("/ping", origin_two.GetURL("/pong")));
1791  origin_two.RegisterRequestHandler(
1792      CreateRedirectHandler("/pong", origin_one.GetURL("/download")));
1793  origin_one.RegisterRequestHandler(CreateBasicResponseHandler(
1794      "/download", "application/octet-stream", "Hello"));
1795
1796  NavigateToURLAndWaitForDownload(
1797      shell(), referrer_url, DownloadItem::COMPLETE);
1798
1799  std::vector<DownloadItem*> downloads;
1800  DownloadManagerForShell(shell())->GetAllDownloads(&downloads);
1801  ASSERT_EQ(1u, downloads.size());
1802
1803  EXPECT_EQ(FILE_PATH_LITERAL("suggested-filename"),
1804            downloads[0]->GetTargetFilePath().BaseName().value());
1805  ASSERT_TRUE(origin_one.ShutdownAndWaitUntilComplete());
1806  ASSERT_TRUE(origin_two.ShutdownAndWaitUntilComplete());
1807}
1808
1809// The file empty.bin is served with a MIME type of application/octet-stream.
1810// The content body is empty. Make sure this case is handled properly and we
1811// don't regress on http://crbug.com/320394.
1812IN_PROC_BROWSER_TEST_F(DownloadContentTest, DownloadGZipWithNoContent) {
1813  EmbeddedTestServer test_server;
1814  ASSERT_TRUE(test_server.InitializeAndWaitUntilReady());
1815
1816  GURL url = test_server.GetURL("/empty.bin");
1817  test_server.ServeFilesFromDirectory(GetTestFilePath("download", ""));
1818
1819  NavigateToURLAndWaitForDownload(shell(), url, DownloadItem::COMPLETE);
1820  // That's it. This should work without crashing.
1821}
1822
1823}  // namespace content
1824