Index: sync/internal_api/attachments/attachment_downloader_impl.cc |
diff --git a/sync/internal_api/attachments/attachment_downloader_impl.cc b/sync/internal_api/attachments/attachment_downloader_impl.cc |
deleted file mode 100644 |
index f0443c1082c8176137176187d0395e6f21b8571b..0000000000000000000000000000000000000000 |
--- a/sync/internal_api/attachments/attachment_downloader_impl.cc |
+++ /dev/null |
@@ -1,296 +0,0 @@ |
-// Copyright 2014 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 "sync/internal_api/public/attachments/attachment_downloader_impl.h" |
- |
-#include <stdint.h> |
-#include <utility> |
- |
-#include "base/base64.h" |
-#include "base/bind.h" |
-#include "base/location.h" |
-#include "base/metrics/histogram.h" |
-#include "base/metrics/histogram_macros.h" |
-#include "base/metrics/sparse_histogram.h" |
-#include "base/single_thread_task_runner.h" |
-#include "base/sys_byteorder.h" |
-#include "base/threading/thread_task_runner_handle.h" |
-#include "base/time/time.h" |
-#include "net/base/load_flags.h" |
-#include "net/http/http_response_headers.h" |
-#include "net/http/http_status_code.h" |
-#include "net/http/http_util.h" |
-#include "net/url_request/url_fetcher.h" |
-#include "net/url_request/url_request_status.h" |
-#include "sync/internal_api/public/attachments/attachment_uploader_impl.h" |
-#include "sync/internal_api/public/attachments/attachment_util.h" |
-#include "sync/protocol/sync.pb.h" |
-#include "url/gurl.h" |
- |
-namespace syncer { |
- |
-struct AttachmentDownloaderImpl::DownloadState { |
- public: |
- DownloadState(const AttachmentId& attachment_id, |
- const AttachmentUrl& attachment_url); |
- |
- AttachmentId attachment_id; |
- AttachmentUrl attachment_url; |
- // |access_token| needed to invalidate if downloading attachment fails with |
- // HTTP_UNAUTHORIZED. |
- std::string access_token; |
- std::unique_ptr<net::URLFetcher> url_fetcher; |
- std::vector<DownloadCallback> user_callbacks; |
- base::TimeTicks start_time; |
-}; |
- |
-AttachmentDownloaderImpl::DownloadState::DownloadState( |
- const AttachmentId& attachment_id, |
- const AttachmentUrl& attachment_url) |
- : attachment_id(attachment_id), attachment_url(attachment_url) { |
-} |
- |
-AttachmentDownloaderImpl::AttachmentDownloaderImpl( |
- const GURL& sync_service_url, |
- const scoped_refptr<net::URLRequestContextGetter>& |
- url_request_context_getter, |
- const std::string& account_id, |
- const OAuth2TokenService::ScopeSet& scopes, |
- const scoped_refptr<OAuth2TokenServiceRequest::TokenServiceProvider>& |
- token_service_provider, |
- const std::string& store_birthday, |
- ModelType model_type) |
- : OAuth2TokenService::Consumer("attachment-downloader-impl"), |
- sync_service_url_(sync_service_url), |
- url_request_context_getter_(url_request_context_getter), |
- account_id_(account_id), |
- oauth2_scopes_(scopes), |
- token_service_provider_(token_service_provider), |
- raw_store_birthday_(store_birthday), |
- model_type_(model_type) { |
- DCHECK(url_request_context_getter_.get()); |
- DCHECK(!account_id.empty()); |
- DCHECK(!scopes.empty()); |
- DCHECK(token_service_provider_.get()); |
- DCHECK(!raw_store_birthday_.empty()); |
-} |
- |
-AttachmentDownloaderImpl::~AttachmentDownloaderImpl() { |
-} |
- |
-void AttachmentDownloaderImpl::DownloadAttachment( |
- const AttachmentId& attachment_id, |
- const DownloadCallback& callback) { |
- DCHECK(CalledOnValidThread()); |
- |
- AttachmentUrl url = AttachmentUploaderImpl::GetURLForAttachmentId( |
- sync_service_url_, attachment_id).spec(); |
- |
- StateMap::iterator iter = state_map_.find(url); |
- DownloadState* download_state = |
- iter != state_map_.end() ? iter->second.get() : nullptr; |
- if (!download_state) { |
- // There is no request started for this attachment id. Let's create |
- // DownloadState and request access token for it. |
- std::unique_ptr<DownloadState> new_download_state( |
- new DownloadState(attachment_id, url)); |
- download_state = new_download_state.get(); |
- state_map_[url] = std::move(new_download_state); |
- RequestAccessToken(download_state); |
- } |
- DCHECK(download_state->attachment_id == attachment_id); |
- download_state->user_callbacks.push_back(callback); |
-} |
- |
-void AttachmentDownloaderImpl::OnGetTokenSuccess( |
- const OAuth2TokenService::Request* request, |
- const std::string& access_token, |
- const base::Time& expiration_time) { |
- DCHECK(CalledOnValidThread()); |
- DCHECK(request == access_token_request_.get()); |
- access_token_request_.reset(); |
- StateList::const_iterator iter; |
- // Start downloads for all download requests waiting for access token. |
- for (iter = requests_waiting_for_access_token_.begin(); |
- iter != requests_waiting_for_access_token_.end(); |
- ++iter) { |
- DownloadState* download_state = *iter; |
- download_state->access_token = access_token; |
- download_state->url_fetcher = |
- CreateFetcher(download_state->attachment_url, access_token); |
- download_state->start_time = base::TimeTicks::Now(); |
- download_state->url_fetcher->Start(); |
- } |
- requests_waiting_for_access_token_.clear(); |
-} |
- |
-void AttachmentDownloaderImpl::OnGetTokenFailure( |
- const OAuth2TokenService::Request* request, |
- const GoogleServiceAuthError& error) { |
- DCHECK(CalledOnValidThread()); |
- DCHECK(request == access_token_request_.get()); |
- access_token_request_.reset(); |
- StateList::const_iterator iter; |
- // Without access token all downloads fail. |
- for (iter = requests_waiting_for_access_token_.begin(); |
- iter != requests_waiting_for_access_token_.end(); |
- ++iter) { |
- DownloadState* download_state = *iter; |
- scoped_refptr<base::RefCountedString> null_attachment_data; |
- ReportResult(*download_state, DOWNLOAD_TRANSIENT_ERROR, |
- null_attachment_data); |
- // Don't delete using the URL directly to avoid an access after free error |
- // due to std::unordered_map's implementation. See crbug.com/603275. |
- auto erase_iter = state_map_.find(download_state->attachment_url); |
- DCHECK(erase_iter != state_map_.end()); |
- state_map_.erase(erase_iter); |
- } |
- requests_waiting_for_access_token_.clear(); |
-} |
- |
-void AttachmentDownloaderImpl::OnURLFetchComplete( |
- const net::URLFetcher* source) { |
- DCHECK(CalledOnValidThread()); |
- |
- // Find DownloadState by url. |
- AttachmentUrl url = source->GetOriginalURL().spec(); |
- StateMap::iterator iter = state_map_.find(url); |
- DCHECK(iter != state_map_.end()); |
- const DownloadState& download_state = *iter->second; |
- DCHECK(source == download_state.url_fetcher.get()); |
- |
- DownloadResult result = DOWNLOAD_TRANSIENT_ERROR; |
- scoped_refptr<base::RefCountedString> attachment_data; |
- uint32_t attachment_crc32c = 0; |
- |
- net::URLRequestStatus status = source->GetStatus(); |
- const int response_code = source->GetResponseCode(); |
- UMA_HISTOGRAM_SPARSE_SLOWLY("Sync.Attachments.DownloadResponseCode", |
- status.is_success() ? response_code : status.error()); |
- if (response_code == net::HTTP_OK) { |
- std::string data_as_string; |
- source->GetResponseAsString(&data_as_string); |
- attachment_data = base::RefCountedString::TakeString(&data_as_string); |
- |
- UMA_HISTOGRAM_LONG_TIMES("Sync.Attachments.DownloadTotalTime", |
- base::TimeTicks::Now() - download_state.start_time); |
- |
- attachment_crc32c = ComputeCrc32c(attachment_data); |
- uint32_t crc32c_from_headers = 0; |
- if (ExtractCrc32c(source->GetResponseHeaders(), &crc32c_from_headers) && |
- attachment_crc32c != crc32c_from_headers) { |
- // Fail download only if there is useful crc32c in header and it doesn't |
- // match data. All other cases are fine. When crc32c is not in headers |
- // locally calculated one will be stored and used for further checks. |
- result = DOWNLOAD_TRANSIENT_ERROR; |
- } else { |
- // If the id's crc32c doesn't match that of the downloaded attachment, |
- // then we're stuck and retrying is unlikely to help. |
- if (attachment_crc32c != download_state.attachment_id.GetCrc32c()) { |
- result = DOWNLOAD_UNSPECIFIED_ERROR; |
- } else { |
- result = DOWNLOAD_SUCCESS; |
- } |
- } |
- UMA_HISTOGRAM_BOOLEAN("Sync.Attachments.DownloadChecksumResult", |
- result == DOWNLOAD_SUCCESS); |
- } else if (response_code == net::HTTP_UNAUTHORIZED) { |
- // Server tells us we've got a bad token so invalidate it. |
- OAuth2TokenServiceRequest::InvalidateToken(token_service_provider_.get(), |
- account_id_, |
- oauth2_scopes_, |
- download_state.access_token); |
- // Fail the request, but indicate that it may be successful if retried. |
- result = DOWNLOAD_TRANSIENT_ERROR; |
- } else if (response_code == net::HTTP_FORBIDDEN) { |
- // User is not allowed to use attachments. Retrying won't help. |
- result = DOWNLOAD_UNSPECIFIED_ERROR; |
- } else if (response_code == net::URLFetcher::RESPONSE_CODE_INVALID) { |
- result = DOWNLOAD_TRANSIENT_ERROR; |
- } |
- ReportResult(download_state, result, attachment_data); |
- state_map_.erase(iter); |
-} |
- |
-std::unique_ptr<net::URLFetcher> AttachmentDownloaderImpl::CreateFetcher( |
- const AttachmentUrl& url, |
- const std::string& access_token) { |
- std::unique_ptr<net::URLFetcher> url_fetcher = |
- net::URLFetcher::Create(GURL(url), net::URLFetcher::GET, this); |
- AttachmentUploaderImpl::ConfigureURLFetcherCommon( |
- url_fetcher.get(), access_token, raw_store_birthday_, model_type_, |
- url_request_context_getter_.get()); |
- return url_fetcher; |
-} |
- |
-void AttachmentDownloaderImpl::RequestAccessToken( |
- DownloadState* download_state) { |
- requests_waiting_for_access_token_.push_back(download_state); |
- // Start access token request if there is no active one. |
- if (access_token_request_ == NULL) { |
- access_token_request_ = OAuth2TokenServiceRequest::CreateAndStart( |
- token_service_provider_.get(), account_id_, oauth2_scopes_, this); |
- } |
-} |
- |
-void AttachmentDownloaderImpl::ReportResult( |
- const DownloadState& download_state, |
- const DownloadResult& result, |
- const scoped_refptr<base::RefCountedString>& attachment_data) { |
- std::vector<DownloadCallback>::const_iterator iter; |
- for (iter = download_state.user_callbacks.begin(); |
- iter != download_state.user_callbacks.end(); |
- ++iter) { |
- std::unique_ptr<Attachment> attachment; |
- if (result == DOWNLOAD_SUCCESS) { |
- attachment.reset(new Attachment(Attachment::CreateFromParts( |
- download_state.attachment_id, attachment_data))); |
- } |
- |
- base::ThreadTaskRunnerHandle::Get()->PostTask( |
- FROM_HERE, base::Bind(*iter, result, base::Passed(&attachment))); |
- } |
-} |
- |
-bool AttachmentDownloaderImpl::ExtractCrc32c( |
- const net::HttpResponseHeaders* headers, |
- uint32_t* crc32c) { |
- DCHECK(crc32c); |
- if (!headers) { |
- return false; |
- } |
- |
- std::string crc32c_encoded; |
- std::string header_value; |
- size_t iter = 0; |
- // Iterate over all matching headers. |
- while (headers->EnumerateHeader(&iter, "x-goog-hash", &header_value)) { |
- // Because EnumerateHeader is smart about list values, header_value will |
- // either be empty or a single name=value pair. |
- net::HttpUtil::NameValuePairsIterator pair_iter( |
- header_value.begin(), header_value.end(), ','); |
- if (pair_iter.GetNext()) { |
- if (pair_iter.name() == "crc32c") { |
- crc32c_encoded = pair_iter.value(); |
- DCHECK(!pair_iter.GetNext()); |
- break; |
- } |
- } |
- } |
- // Check if header was found |
- if (crc32c_encoded.empty()) |
- return false; |
- std::string crc32c_raw; |
- if (!base::Base64Decode(crc32c_encoded, &crc32c_raw)) |
- return false; |
- |
- if (crc32c_raw.size() != sizeof(*crc32c)) |
- return false; |
- |
- *crc32c = |
- base::NetToHost32(*reinterpret_cast<const uint32_t*>(crc32c_raw.c_str())); |
- return true; |
-} |
- |
-} // namespace syncer |