Chromium Code Reviews| 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..60841d2bd3bc6d15ae7111f4081c6ddb766be14a |
| --- /dev/null |
| +++ b/content/browser/download/url_downloader.cc |
| @@ -0,0 +1,199 @@ |
| +// Copyright 2015 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/location.h" |
| +#include "base/thread_task_runner_handle.h" |
| +#include "content/browser/appcache/appcache_interceptor.h" |
| +#include "content/browser/service_worker/service_worker_request_handler.h" |
| +#include "content/browser/ssl/ssl_policy.h" |
| +#include "content/common/ssl_status_serialization.h" |
| +#include "content/public/browser/cert_store.h" |
| +#include "content/public/browser/download_save_info.h" |
| +#include "content/public/browser/signed_certificate_timestamp_store.h" |
| +#include "content/public/common/process_type.h" |
| +#include "content/public/common/security_style.h" |
| +#include "net/base/io_buffer.h" |
| +#include "net/base/load_flags.h" |
| +#include "net/base/net_errors.h" |
| +#include "net/http/http_response_headers.h" |
| +#include "net/http/http_status_code.h" |
| +#include "ui/base/page_transition_types.h" |
| + |
| +namespace content { |
| + |
| +scoped_ptr<UrlDownloader> UrlDownloader::BeginDownload( |
|
asanka
2015/12/08 16:58:33
// static
above this line.
svaldez
2015/12/08 20:39:26
Done.
|
| + base::WeakPtr<DownloadManagerImpl> download_manager, |
| + scoped_ptr<net::URLRequest> request, |
| + const Referrer& referrer, |
| + bool is_content_initiated, |
| + bool prefer_cache, |
| + bool do_not_prompt_for_login, |
| + scoped_ptr<DownloadSaveInfo> save_info, |
| + uint32 download_id, |
| + const DownloadUrlParameters::OnStartedCallback& started_callback) { |
| + if (!referrer.url.is_valid()) |
| + request->SetReferrer(std::string()); |
| + else |
| + request->SetReferrer(referrer.url.spec()); |
| + |
| + int extra_load_flags = net::LOAD_NORMAL; |
| + if (prefer_cache) { |
| + // If there is upload data attached, only retrieve from cache because there |
| + // is no current mechanism to prompt the user for their consent for a |
| + // re-post. For GETs, try to retrieve data from the cache and skip |
| + // validating the entry if present. |
| + if (request->get_upload() != NULL) |
| + extra_load_flags |= net::LOAD_ONLY_FROM_CACHE; |
| + else |
| + extra_load_flags |= net::LOAD_PREFERRING_CACHE; |
| + } else { |
| + extra_load_flags |= net::LOAD_DISABLE_CACHE; |
| + } |
| + request->SetLoadFlags(request->load_flags() | extra_load_flags); |
| + |
| + // We treat a download as a main frame load, and thus update the policy URL on |
| + // redirects. |
| + // |
| + // TODO(davidben): Is this correct? If this came from a |
| + // ViewHostMsg_DownloadUrl in a frame, should it have first-party URL set |
| + // appropriately? |
|
asanka
2015/12/08 16:58:33
This was done for downloads because we wanted to t
svaldez
2015/12/08 20:39:26
Done.
|
| + request->set_first_party_url_policy( |
| + net::URLRequest::UPDATE_FIRST_PARTY_URL_ON_REDIRECT); |
| + |
| + if (request->url().SchemeIs(url::kBlobScheme)) |
| + return nullptr; |
| + |
| + scoped_ptr<DownloadRequestCore> handler(new DownloadRequestCore( |
| + download_id, request.get(), started_callback, save_info.Pass(), |
| + download_manager)); |
| + |
| + // From this point forward, the |UrlDownloader| is responsible for |
| + // |started_callback|. |
| + scoped_ptr<UrlDownloader> downloader( |
| + new UrlDownloader(request.Pass(), handler.Pass())); |
| + |
| + downloader->Start(); |
| + |
| + return downloader; |
| +} |
| + |
| +UrlDownloader::UrlDownloader(scoped_ptr<net::URLRequest> request, |
| + scoped_ptr<DownloadRequestCore> handler) |
| + : request_(request.Pass()), |
| + handler_(handler.Pass()), |
| + weak_ptr_factory_(this) {} |
| + |
| +UrlDownloader::~UrlDownloader() { |
| + handler_.reset(); |
| +} |
| + |
| +void UrlDownloader::Start() { |
| + DCHECK(!request_->is_pending()); |
| + |
| + if (!request_->status().is_success()) { |
|
asanka
2015/12/08 16:58:33
Nit: no {
Also, do you know when this would be tr
svaldez
2015/12/08 20:39:26
Requests which are prematurely killed? Copied from
|
| + return; |
| + } |
| + |
| + request_->set_delegate(this); |
| + request_->Start(); |
| +} |
| + |
| +void UrlDownloader::OnReceivedRedirect(net::URLRequest* request, |
| + const net::RedirectInfo& redirect_info, |
| + bool* defer_redirect) { |
| + DVLOG(1) << "OnReceivedRedirect: " << request_->url().spec(); |
| + request_->CancelWithError(net::ERR_ABORTED); |
| +} |
| + |
| +void UrlDownloader::OnResponseStarted(net::URLRequest* request) { |
| + DVLOG(1) << "OnResponseStarted: " << request_->url().spec(); |
| + |
| + if (!request_->status().is_success()) { |
| + ResponseCompleted(); |
| + return; |
| + } |
| + |
| + handler_->OnResponseStarted(); |
| + |
| + if (request_->status().is_success()) |
|
asanka
2015/12/08 16:58:33
I'm guessing you are copying logic in ResourceLoad
svaldez
2015/12/08 20:39:26
Acknowledged.
|
| + StartReading(false); // Read the first chunk. |
| + else |
| + ResponseCompleted(); |
| +} |
| + |
| +void UrlDownloader::OnReadCompleted(net::URLRequest* request, int bytes_read) { |
|
asanka
2015/12/08 16:58:33
Nit: let's move OnReadCompleted below StartReading
svaldez
2015/12/08 20:39:26
Done.
|
| + DVLOG(1) << "OnReadCompleted: \"" << request_->url().spec() << "\"" |
| + << " bytes_read = " << bytes_read; |
| + |
| + // bytes_read == -1 always implies an error. |
| + if (bytes_read == -1 || !request_->status().is_success()) { |
| + ResponseCompleted(); |
| + return; |
| + } |
| + |
| + DCHECK(bytes_read >= 0); |
| + DCHECK(request_->status().is_success()); |
| + |
| + bool defer = false; |
| + if (!handler_->OnReadCompleted(bytes_read, &defer)) { |
| + request_->CancelWithError(net::ERR_ABORTED); |
| + return; |
| + } |
| + DCHECK(!defer); |
|
asanka
2015/12/08 16:58:33
This is not correct. The ByteStreamWriter can requ
svaldez
2015/12/08 20:39:26
Done.
|
| + |
| + if (!request_->status().is_success()) |
| + return; |
| + |
| + if (bytes_read > 0) { |
| + StartReading(true); // Read the next chunk. |
| + } else { |
| + // URLRequest reported an EOF. Call ResponseCompleted. |
| + DCHECK_EQ(0, bytes_read); |
| + ResponseCompleted(); |
| + } |
| +} |
| + |
| +void UrlDownloader::StartReading(bool is_continuation) { |
| + int bytes_read; |
| + |
| + // Make sure we track the buffer in at least one place. This ensures it gets |
| + // deleted even in the case the request has already finished its job and |
| + // doesn't use the buffer. |
| + scoped_refptr<net::IOBuffer> buf; |
| + int buf_size; |
| + if (!handler_->OnWillRead(&buf, &buf_size, -1)) { |
| + request_->CancelWithError(net::ERR_ABORTED); |
| + return; |
|
asanka
2015/12/08 16:58:33
How does OnResponseCompleted() get called in this
svaldez
2015/12/08 20:39:26
Done.
|
| + } |
| + |
| + DCHECK(buf.get()); |
| + DCHECK(buf_size > 0); |
| + |
| + request_->Read(buf.get(), buf_size, &bytes_read); |
| + |
| + // If IO is pending, wait for the URLRequest to call OnReadCompleted. |
| + if (request_->status().is_io_pending()) |
| + return; |
| + |
| + if (!is_continuation || bytes_read <= 0) { |
| + OnReadCompleted(request_.get(), bytes_read); |
| + } else { |
| + // Else, trigger OnReadCompleted asynchronously to avoid starving the IO |
| + // thread in case the URLRequest can provide data synchronously. |
| + base::ThreadTaskRunnerHandle::Get()->PostTask( |
| + FROM_HERE, |
| + base::Bind(&UrlDownloader::OnReadCompleted, |
| + weak_ptr_factory_.GetWeakPtr(), request_.get(), bytes_read)); |
| + } |
| +} |
| + |
| +void UrlDownloader::ResponseCompleted() { |
| + DVLOG(1) << "ResponseCompleted: " << request_->url().spec(); |
| + |
| + handler_->OnResponseCompleted(request_->status()); |
|
asanka
2015/12/08 16:58:33
We should discard handler_ after this point since
svaldez
2015/12/08 20:39:26
Done.
|
| +} |
| + |
| +} // namespace content |