Created
April 15, 2017 18:24
-
-
Save bartoszalksnin/a7652bedad431ea2badf6418d811d7be to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From fa8c1190b9e60c863014f6b4717ac0e6147e9c84 Mon Sep 17 00:00:00 2001 | |
From: =?UTF-8?q?=C2=A8Bartosz?= <¨bartek@gopromo.pl¨> | |
Date: Sat, 15 Apr 2017 19:17:15 +0100 | |
Subject: [PATCH] enable download for headless mode | |
--- | |
headless/BUILD.gn | 2 + | |
.../lib/browser/headless_browser_context_impl.cc | 8 +- | |
.../lib/browser/headless_browser_context_impl.h | 2 + | |
.../browser/headless_browser_download_delegate.cc | 168 +++++++++++++++++++++ | |
.../browser/headless_browser_download_delegate.h | 67 ++++++++ | |
5 files changed, 246 insertions(+), 1 deletion(-) | |
create mode 100644 headless/lib/browser/headless_browser_download_delegate.cc | |
create mode 100644 headless/lib/browser/headless_browser_download_delegate.h | |
diff --git a/headless/BUILD.gn b/headless/BUILD.gn | |
index 55afe1f..8f8c94f 100644 | |
--- a/headless/BUILD.gn | |
+++ b/headless/BUILD.gn | |
@@ -210,6 +210,8 @@ static_library("headless_lib") { | |
"lib/browser/headless_browser_context_impl.h", | |
"lib/browser/headless_browser_context_options.cc", | |
"lib/browser/headless_browser_context_options.h", | |
+ "lib/browser/headless_browser_download_delegate.cc", | |
+ "lib/browser/headless_browser_download_delegate.h", | |
"lib/browser/headless_browser_impl.cc", | |
"lib/browser/headless_browser_impl.h", | |
"lib/browser/headless_browser_impl_mac.mm", | |
diff --git a/headless/lib/browser/headless_browser_context_impl.cc b/headless/lib/browser/headless_browser_context_impl.cc | |
index b691760..8155d58 100644 | |
--- a/headless/lib/browser/headless_browser_context_impl.cc | |
+++ b/headless/lib/browser/headless_browser_context_impl.cc | |
@@ -178,7 +178,13 @@ content::ResourceContext* HeadlessBrowserContextImpl::GetResourceContext() { | |
content::DownloadManagerDelegate* | |
HeadlessBrowserContextImpl::GetDownloadManagerDelegate() { | |
- return nullptr; | |
+ if (!download_delegate_.get()) { | |
+ download_delegate_.reset(new HeadlessBrowserDownloadDelegate()); | |
+ download_delegate_->SetDownloadManager( | |
+ content::BrowserContext::GetDownloadManager(this)); | |
+ } | |
+ | |
+ return download_delegate_.get(); | |
} | |
content::BrowserPluginGuestManager* | |
diff --git a/headless/lib/browser/headless_browser_context_impl.h b/headless/lib/browser/headless_browser_context_impl.h | |
index 6882449..5fbc976 100644 | |
--- a/headless/lib/browser/headless_browser_context_impl.h | |
+++ b/headless/lib/browser/headless_browser_context_impl.h | |
@@ -18,6 +18,7 @@ | |
#include "headless/lib/browser/headless_url_request_context_getter.h" | |
#include "headless/public/headless_browser.h" | |
#include "headless/public/headless_browser_context.h" | |
+#include "headless/lib/browser/headless_browser_download_delegate.h" | |
namespace headless { | |
class HeadlessBrowserImpl; | |
@@ -93,6 +94,7 @@ class HeadlessBrowserContextImpl : public HeadlessBrowserContext, | |
HeadlessBrowserImpl* browser_; // Not owned. | |
std::unique_ptr<HeadlessBrowserContextOptions> context_options_; | |
std::unique_ptr<HeadlessResourceContext> resource_context_; | |
+ std::unique_ptr<HeadlessBrowserDownloadDelegate> download_delegate_; | |
base::FilePath path_; | |
std::unordered_map<std::string, std::unique_ptr<HeadlessWebContents>> | |
diff --git a/headless/lib/browser/headless_browser_download_delegate.cc b/headless/lib/browser/headless_browser_download_delegate.cc | |
new file mode 100644 | |
index 0000000..dcdc24d | |
--- /dev/null | |
+++ b/headless/lib/browser/headless_browser_download_delegate.cc | |
@@ -0,0 +1,168 @@ | |
+// Copyright 2013 The Chromium Authors. All rights reserved. | |
+// Use of this source code is governed by a BSD-style license that can be | |
+// found in the LICENSE file. | |
+ | |
+#include "headless/lib/browser/headless_browser_download_delegate.h" | |
+ | |
+#if defined(OS_WIN) | |
+#include <commdlg.h> | |
+#include <windows.h> | |
+#endif | |
+ | |
+#include "base/bind.h" | |
+#include "base/command_line.h" | |
+#include "base/files/file_util.h" | |
+#include "base/logging.h" | |
+#include "base/macros.h" | |
+#include "base/strings/string_util.h" | |
+#include "base/strings/utf_string_conversions.h" | |
+#include "build/build_config.h" | |
+#include "content/public/browser/browser_context.h" | |
+#include "content/public/browser/browser_thread.h" | |
+#include "content/public/browser/download_manager.h" | |
+#include "content/public/browser/web_contents.h" | |
+#include "net/base/filename_util.h" | |
+ | |
+#if defined(OS_WIN) | |
+#include "ui/aura/window.h" | |
+#include "ui/aura/window_tree_host.h" | |
+#endif | |
+ | |
+namespace headless { | |
+ | |
+HeadlessBrowserDownloadDelegate::HeadlessBrowserDownloadDelegate() | |
+ : download_manager_(NULL), | |
+ suppress_prompting_(false), | |
+ weak_ptr_factory_(this) {} | |
+ | |
+HeadlessBrowserDownloadDelegate::~HeadlessBrowserDownloadDelegate() { | |
+ if (download_manager_) { | |
+ DCHECK_EQ(static_cast<content::DownloadManagerDelegate*>(this), | |
+ download_manager_->GetDelegate()); | |
+ download_manager_->SetDelegate(NULL); | |
+ download_manager_ = NULL; | |
+ } | |
+} | |
+ | |
+void HeadlessBrowserDownloadDelegate::SetDownloadManager( | |
+ content::DownloadManager* download_manager) { | |
+ download_manager_ = download_manager; | |
+} | |
+ | |
+void HeadlessBrowserDownloadDelegate::Shutdown() { | |
+ // Revoke any pending callbacks. download_manager_ et. al. are no longer safe | |
+ // to access after this point. | |
+ weak_ptr_factory_.InvalidateWeakPtrs(); | |
+ download_manager_ = NULL; | |
+} | |
+ | |
+bool HeadlessBrowserDownloadDelegate::DetermineDownloadTarget( | |
+ content::DownloadItem* download, | |
+ const content::DownloadTargetCallback& callback) { | |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
+ // This assignment needs to be here because even at the call to | |
+ // SetDownloadManager, the system is not fully initialized. | |
+ if (default_download_path_.empty()) { | |
+ default_download_path_ = | |
+ download_manager_->GetBrowserContext()->GetPath().Append( | |
+ FILE_PATH_LITERAL("Downloads")); | |
+ } | |
+ | |
+ if (!download->GetForcedFilePath().empty()) { | |
+ callback.Run(download->GetForcedFilePath(), | |
+ content::DownloadItem::TARGET_DISPOSITION_OVERWRITE, | |
+ content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, | |
+ download->GetForcedFilePath(), | |
+ content::DownloadInterruptReason::DOWNLOAD_INTERRUPT_REASON_NONE); | |
+ return true; | |
+ } | |
+ | |
+ FilenameDeterminedCallback filename_determined_callback = | |
+ base::Bind(&HeadlessBrowserDownloadDelegate::OnDownloadPathGenerated, | |
+ weak_ptr_factory_.GetWeakPtr(), download->GetId(), callback); | |
+ | |
+ content::BrowserThread::PostTask( | |
+ content::BrowserThread::FILE, FROM_HERE, | |
+ base::Bind(&HeadlessBrowserDownloadDelegate::GenerateFilename, | |
+ download->GetURL(), download->GetContentDisposition(), | |
+ download->GetSuggestedFilename(), download->GetMimeType(), | |
+ default_download_path_, filename_determined_callback)); | |
+ return true; | |
+} | |
+ | |
+bool HeadlessBrowserDownloadDelegate::ShouldOpenDownload( | |
+ content::DownloadItem* item, | |
+ const content::DownloadOpenDelayedCallback& callback) { | |
+ return true; | |
+} | |
+ | |
+void HeadlessBrowserDownloadDelegate::GetNextId( | |
+ const content::DownloadIdCallback& callback) { | |
+ static uint32_t next_id = content::DownloadItem::kInvalidId + 1; | |
+ callback.Run(next_id++); | |
+} | |
+ | |
+// static | |
+void HeadlessBrowserDownloadDelegate::GenerateFilename( | |
+ const GURL& url, | |
+ const std::string& content_disposition, | |
+ const std::string& suggested_filename, | |
+ const std::string& mime_type, | |
+ const base::FilePath& suggested_directory, | |
+ const FilenameDeterminedCallback& callback) { | |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::FILE); | |
+ base::FilePath generated_name = | |
+ net::GenerateFileName(url, content_disposition, std::string(), | |
+ suggested_filename, mime_type, "download"); | |
+ | |
+ if (!base::PathExists(suggested_directory)) | |
+ base::CreateDirectory(suggested_directory); | |
+ | |
+ base::FilePath suggested_path(suggested_directory.Append(generated_name)); | |
+ content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, | |
+ base::Bind(callback, suggested_path)); | |
+} | |
+ | |
+void HeadlessBrowserDownloadDelegate::OnDownloadPathGenerated( | |
+ uint32_t download_id, | |
+ const content::DownloadTargetCallback& callback, | |
+ const base::FilePath& suggested_path) { | |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
+ if (suppress_prompting_ || true) { | |
+ // Testing exit. | |
+ callback.Run(suggested_path, | |
+ content::DownloadItem::TARGET_DISPOSITION_OVERWRITE, | |
+ content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, | |
+ suggested_path.AddExtension(FILE_PATH_LITERAL(".crdownload")), | |
+ content::DownloadInterruptReason::DOWNLOAD_INTERRUPT_REASON_NONE); | |
+ return; | |
+ } | |
+ | |
+ ChooseDownloadPath(download_id, callback, suggested_path); | |
+} | |
+ | |
+void HeadlessBrowserDownloadDelegate::ChooseDownloadPath( | |
+ uint32_t download_id, | |
+ const content::DownloadTargetCallback& callback, | |
+ const base::FilePath& suggested_path) { | |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
+ content::DownloadItem* item = download_manager_->GetDownload(download_id); | |
+ if (!item || (item->GetState() != content::DownloadItem::IN_PROGRESS)) | |
+ return; | |
+ | |
+ base::FilePath result; | |
+ | |
+ result = base::FilePath(suggested_path.value()); | |
+ | |
+ callback.Run(result, content::DownloadItem::TARGET_DISPOSITION_PROMPT, | |
+ content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, result, | |
+ content::DownloadInterruptReason::DOWNLOAD_INTERRUPT_REASON_NONE); | |
+} | |
+ | |
+void HeadlessBrowserDownloadDelegate::SetDownloadBehaviorForTesting( | |
+ const base::FilePath& default_download_path) { | |
+ default_download_path_ = default_download_path; | |
+ suppress_prompting_ = true; | |
+} | |
+ | |
+} // namespace content | |
diff --git a/headless/lib/browser/headless_browser_download_delegate.h b/headless/lib/browser/headless_browser_download_delegate.h | |
new file mode 100644 | |
index 0000000..ccbea7a | |
--- /dev/null | |
+++ b/headless/lib/browser/headless_browser_download_delegate.h | |
@@ -0,0 +1,67 @@ | |
+// Copyright 2013 The Chromium Authors. All rights reserved. | |
+// Use of this source code is governed by a BSD-style license that can be | |
+// found in the LICENSE file. | |
+ | |
+#ifndef CONTENT_HEADLESS_BROWSER_SHELL_DOWNLOAD_MANAGER_DELEGATE_H_ | |
+#define CONTENT_HEADLESS_BROWSER_SHELL_DOWNLOAD_MANAGER_DELEGATE_H_ | |
+ | |
+#include <stdint.h> | |
+ | |
+#include "base/callback_forward.h" | |
+#include "base/compiler_specific.h" | |
+#include "base/macros.h" | |
+#include "base/memory/weak_ptr.h" | |
+#include "content/public/browser/download_manager_delegate.h" | |
+ | |
+namespace headless { | |
+ | |
+class DownloadManager; | |
+ | |
+class HeadlessBrowserDownloadDelegate : public content::DownloadManagerDelegate { | |
+ public: | |
+ HeadlessBrowserDownloadDelegate(); | |
+ ~HeadlessBrowserDownloadDelegate() override; | |
+ | |
+ void SetDownloadManager(content::DownloadManager* manager); | |
+ | |
+ void Shutdown() override; | |
+ bool DetermineDownloadTarget(content::DownloadItem* download, | |
+ const content::DownloadTargetCallback& callback) override; | |
+ bool ShouldOpenDownload(content::DownloadItem* item, | |
+ const content::DownloadOpenDelayedCallback& callback) override; | |
+ void GetNextId(const content::DownloadIdCallback& callback) override; | |
+ | |
+ // Inhibits prompting and sets the default download path. | |
+ void SetDownloadBehaviorForTesting( | |
+ const base::FilePath& default_download_path); | |
+ | |
+ private: | |
+ friend class base::RefCountedThreadSafe<HeadlessBrowserDownloadDelegate>; | |
+ | |
+ typedef base::Callback<void(const base::FilePath&)> | |
+ FilenameDeterminedCallback; | |
+ | |
+ static void GenerateFilename(const GURL& url, | |
+ const std::string& content_disposition, | |
+ const std::string& suggested_filename, | |
+ const std::string& mime_type, | |
+ const base::FilePath& suggested_directory, | |
+ const FilenameDeterminedCallback& callback); | |
+ void OnDownloadPathGenerated(uint32_t download_id, | |
+ const content::DownloadTargetCallback& callback, | |
+ const base::FilePath& suggested_path); | |
+ void ChooseDownloadPath(uint32_t download_id, | |
+ const content::DownloadTargetCallback& callback, | |
+ const base::FilePath& suggested_path); | |
+ | |
+ content::DownloadManager* download_manager_; | |
+ base::FilePath default_download_path_; | |
+ bool suppress_prompting_; | |
+ base::WeakPtrFactory<HeadlessBrowserDownloadDelegate> weak_ptr_factory_; | |
+ | |
+ DISALLOW_COPY_AND_ASSIGN(HeadlessBrowserDownloadDelegate); | |
+}; | |
+ | |
+} // namespace content | |
+ | |
+#endif // CONTENT_SHELL_BROWSER_SHELL_DOWNLOAD_MANAGER_DELEGATE_H_ | |
-- | |
2.7.4 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment