Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(449)

Unified Diff: content/browser/download/url_downloader.cc

Issue 23496076: WIP - Refactor programmatic downloads Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « content/browser/download/url_downloader.h ('k') | content/browser/download/url_downloader_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: content/browser/download/url_downloader.cc
diff --git a/content/browser/download/url_downloader.cc b/content/browser/download/url_downloader.cc
new file mode 100644
index 0000000000000000000000000000000000000000..fd6d0dfdc4ed8ea9f18c67384974bd240492d5e1
--- /dev/null
+++ b/content/browser/download/url_downloader.cc
@@ -0,0 +1,233 @@
+// 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 "content/browser/download/url_downloader.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "content/browser/download/download_create_info.h"
+#include "content/browser/download/download_interrupt_reasons_impl.h"
+#include "content/browser/download/download_request_handle.h"
+#include "content/browser/download/download_request_model.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/download_url_parameters.h"
+#include "net/url_request/url_request.h"
+
+namespace content {
+
+class UrlDownloader::RequestHandle : public DownloadRequestHandle {
+ public:
+ RequestHandle(scoped_ptr<UrlDownloader> downloader);
+ virtual ~RequestHandle();
+
+ private:
+ // DownloadRequestHandle.
+ virtual void Start(const RequestStartedCallback& callback) OVERRIDE;
+ virtual void PauseRequest() const OVERRIDE;
+ virtual void ResumeRequest() const OVERRIDE;
+ virtual void CancelRequest() const OVERRIDE;
+ virtual std::string DebugString() const OVERRIDE;
+
+ scoped_ptr<UrlDownloader> downloader_;
+
+ DISALLOW_COPY_AND_ASSIGN(RequestHandle);
+};
+
+UrlDownloader::RequestHandle::RequestHandle(
+ scoped_ptr<UrlDownloader> downloader)
+ : downloader_(downloader.Pass()) {}
+
+UrlDownloader::RequestHandle::~RequestHandle() {
+ BrowserThread::DeleteSoon(
+ BrowserThread::IO, FROM_HERE, downloader_.release());
+}
+
+void UrlDownloader::RequestHandle::Start(
+ const RequestStartedCallback& callback) {
+ BrowserThread::PostTask(BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&UrlDownloader::Start,
+ base::Unretained(downloader_.get()),
+ callback));
+}
+
+void UrlDownloader::RequestHandle::PauseRequest() const {
+ BrowserThread::PostTask(BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&UrlDownloader::PauseRequest,
+ base::Unretained(downloader_.get())));
+}
+
+void UrlDownloader::RequestHandle::ResumeRequest() const {
+ BrowserThread::PostTask(BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&UrlDownloader::ResumeRequest,
+ base::Unretained(downloader_.get())));
+}
+
+void UrlDownloader::RequestHandle::CancelRequest() const {
+ BrowserThread::PostTask(BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&UrlDownloader::CancelRequest,
+ base::Unretained(downloader_.get())));
+}
+
+std::string UrlDownloader::RequestHandle::DebugString() const {
+ return std::string();
+}
+
+// static
+scoped_ptr<DownloadRequestHandle> UrlDownloader::CreateDownloadRequest(
+ scoped_ptr<DownloadUrlParameters> params) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ scoped_ptr<UrlDownloader> downloader(new UrlDownloader(params.Pass()));
+ scoped_ptr<DownloadRequestHandle> request_handle(
+ new RequestHandle(downloader.Pass()));
+ return request_handle.Pass();
+}
+
+UrlDownloader::UrlDownloader(scoped_ptr<DownloadUrlParameters> params)
+ : params_(params.Pass()),
+ child_process_id_(params_->render_process_host_id()),
+ is_request_active_(true) {
+ // Can be created on the UI thread.
+}
+
+UrlDownloader::~UrlDownloader() {}
+
+void UrlDownloader::Start(const RequestStartedCallback& callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ started_callback_ = callback;
+ request_ = DownloadRequestModel::CreateRequest(*params_, this).Pass();
+ if (!request_) {
+ scoped_ptr<DownloadCreateInfo> empty_create_info;
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(callback,
+ DOWNLOAD_INTERRUPT_REASON_NETWORK_INVALID_REQUEST,
+ base::Passed(&empty_create_info)));
+ return;
+ }
+
+ scoped_ptr<DownloadSaveInfo> save_info(new DownloadSaveInfo());
+ save_info->file_path = params_->file_path();
+ save_info->suggested_name = params_->suggested_name();
+ save_info->offset = params_->offset();
+ save_info->hash_state = params_->hash_state();
+ save_info->prompt_for_save_location = params_->prompt();
+ save_info->file_stream = params_->GetFileStream();
+
+ // TODO(asanka): This request will not have the LOAD_MAYBE_USER_GESTURE flag
+ // set. This is correct since this is a programmatic download. Make sure that
+ // this doesn't affect resumption since a download that was considered safe
+ // before may be considered dangerous on resumption.
+
+ request_model_.reset(
+ new DownloadRequestModel(request_.get(), save_info.Pass()));
+ request_->Start();
+}
+
+void UrlDownloader::OnReceivedRedirect(net::URLRequest* request,
+ const GURL& new_url,
+ bool* defer_redirect) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (!DownloadRequestModel::IsRequestAllowed(new_url, child_process_id_)) {
+ request_model_->OnDownloadInterrupted(
+ DOWNLOAD_INTERRUPT_REASON_NETWORK_INVALID_REQUEST);
+ request_->Cancel();
+ return;
+ }
+ request_model_->OnRequestRedirected(new_url);
+}
+
+void UrlDownloader::OnResponseStarted(net::URLRequest* request) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (!request_->status().is_success()) {
+ DownloadInterruptReason reason = ConvertNetErrorToInterruptReason(
+ static_cast<net::Error>(request_->status().error()),
+ DOWNLOAD_INTERRUPT_FROM_NETWORK);
+ scoped_ptr<DownloadCreateInfo> empty_create_info;
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(
+ started_callback_, reason, base::Passed(&empty_create_info)));
+ request_->Cancel();
+ return;
+ }
+
+ scoped_ptr<DownloadCreateInfo> create_info =
+ request_model_->OnResponseStarted(
+ std::string(),
+ false,
+ PAGE_TRANSITION_LINK,
+ base::Bind(&UrlDownloader::ResumeRequest, base::Unretained(this)));
+ BrowserThread::PostTask(BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(started_callback_,
+ DOWNLOAD_INTERRUPT_REASON_NONE,
+ base::Passed(&create_info)));
+ ReadNextChunk();
+}
+
+void UrlDownloader::OnReadCompleted(net::URLRequest* request, int bytes_read) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ HandleCompletedRead(bytes_read);
+ ReadNextChunk();
+}
+
+void UrlDownloader::PauseRequest() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ request_model_->OnPauseRequest();
+}
+
+void UrlDownloader::ResumeRequest() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (request_model_->OnResumeRequest() ==
+ DownloadRequestModel::READY_TO_READ &&
+ !is_request_active_ &&
+ request_->status().is_success())
+ ReadNextChunk();
+}
+
+void UrlDownloader::CancelRequest() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ request_->Cancel();
+}
+
+void UrlDownloader::ReadNextChunk() {
+ net::IOBuffer* buffer = NULL;
+ int buf_size = 0;
+ int bytes_read = 0;
+ bool read_succeeded = false;
+
+ if (!is_request_active_)
+ return;
+
+ do {
+ request_model_->OnWillRead(&buffer, &buf_size, -1);
+ DCHECK_LT(0, buf_size);
+
+ // TODO(asanka): Check for re-entrancy issues. Can Read() result in a call
+ // into OnReadCompleted()?
+ read_succeeded = request_->Read(buffer, buf_size, &bytes_read);
+
+ // Read returns false if IO is pending or if the read failed.
+ if (read_succeeded || !request_->status().is_success())
+ HandleCompletedRead(bytes_read);
+ } while(read_succeeded && is_request_active_);
+}
+
+void UrlDownloader::HandleCompletedRead(int bytes_read) {
+ DownloadRequestModel::ReadState read_state =
+ request_model_->OnReadCompleted(bytes_read);
+ is_request_active_ = (read_state == DownloadRequestModel::READY_TO_READ);
+ if (bytes_read == 0 || !request_->status().is_success()) {
+ request_model_->OnResponseCompleted();
+ is_request_active_ = false;
+ }
+}
+
+} // namespace content
« no previous file with comments | « content/browser/download/url_downloader.h ('k') | content/browser/download/url_downloader_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698