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

Side by Side Diff: components/sync/core_impl/attachments/attachment_downloader_impl.cc

Issue 2130453004: [Sync] Move //sync to //components/sync. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase. Created 4 years, 4 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 unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "sync/internal_api/public/attachments/attachment_downloader_impl.h" 5 #include "components/sync/core/attachments/attachment_downloader_impl.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8
8 #include <utility> 9 #include <utility>
9 10
10 #include "base/base64.h" 11 #include "base/base64.h"
11 #include "base/bind.h" 12 #include "base/bind.h"
12 #include "base/location.h" 13 #include "base/location.h"
13 #include "base/metrics/histogram.h" 14 #include "base/metrics/histogram.h"
14 #include "base/metrics/histogram_macros.h" 15 #include "base/metrics/histogram_macros.h"
15 #include "base/metrics/sparse_histogram.h" 16 #include "base/metrics/sparse_histogram.h"
16 #include "base/single_thread_task_runner.h" 17 #include "base/single_thread_task_runner.h"
17 #include "base/sys_byteorder.h" 18 #include "base/sys_byteorder.h"
18 #include "base/threading/thread_task_runner_handle.h" 19 #include "base/threading/thread_task_runner_handle.h"
19 #include "base/time/time.h" 20 #include "base/time/time.h"
21 #include "components/sync/core/attachments/attachment_uploader_impl.h"
22 #include "components/sync/core/attachments/attachment_util.h"
23 #include "components/sync/protocol/sync.pb.h"
20 #include "net/base/load_flags.h" 24 #include "net/base/load_flags.h"
21 #include "net/http/http_response_headers.h" 25 #include "net/http/http_response_headers.h"
22 #include "net/http/http_status_code.h" 26 #include "net/http/http_status_code.h"
23 #include "net/http/http_util.h" 27 #include "net/http/http_util.h"
24 #include "net/url_request/url_fetcher.h" 28 #include "net/url_request/url_fetcher.h"
25 #include "net/url_request/url_request_status.h" 29 #include "net/url_request/url_request_status.h"
26 #include "sync/internal_api/public/attachments/attachment_uploader_impl.h"
27 #include "sync/internal_api/public/attachments/attachment_util.h"
28 #include "sync/protocol/sync.pb.h"
29 #include "url/gurl.h" 30 #include "url/gurl.h"
30 31
31 namespace syncer { 32 namespace syncer {
32 33
33 struct AttachmentDownloaderImpl::DownloadState { 34 struct AttachmentDownloaderImpl::DownloadState {
34 public: 35 public:
35 DownloadState(const AttachmentId& attachment_id, 36 DownloadState(const AttachmentId& attachment_id,
36 const AttachmentUrl& attachment_url); 37 const AttachmentUrl& attachment_url);
37 38
38 AttachmentId attachment_id; 39 AttachmentId attachment_id;
39 AttachmentUrl attachment_url; 40 AttachmentUrl attachment_url;
40 // |access_token| needed to invalidate if downloading attachment fails with 41 // |access_token| needed to invalidate if downloading attachment fails with
41 // HTTP_UNAUTHORIZED. 42 // HTTP_UNAUTHORIZED.
42 std::string access_token; 43 std::string access_token;
43 std::unique_ptr<net::URLFetcher> url_fetcher; 44 std::unique_ptr<net::URLFetcher> url_fetcher;
44 std::vector<DownloadCallback> user_callbacks; 45 std::vector<DownloadCallback> user_callbacks;
45 base::TimeTicks start_time; 46 base::TimeTicks start_time;
46 }; 47 };
47 48
48 AttachmentDownloaderImpl::DownloadState::DownloadState( 49 AttachmentDownloaderImpl::DownloadState::DownloadState(
49 const AttachmentId& attachment_id, 50 const AttachmentId& attachment_id,
50 const AttachmentUrl& attachment_url) 51 const AttachmentUrl& attachment_url)
51 : attachment_id(attachment_id), attachment_url(attachment_url) { 52 : attachment_id(attachment_id), attachment_url(attachment_url) {}
52 }
53 53
54 AttachmentDownloaderImpl::AttachmentDownloaderImpl( 54 AttachmentDownloaderImpl::AttachmentDownloaderImpl(
55 const GURL& sync_service_url, 55 const GURL& sync_service_url,
56 const scoped_refptr<net::URLRequestContextGetter>& 56 const scoped_refptr<net::URLRequestContextGetter>&
57 url_request_context_getter, 57 url_request_context_getter,
58 const std::string& account_id, 58 const std::string& account_id,
59 const OAuth2TokenService::ScopeSet& scopes, 59 const OAuth2TokenService::ScopeSet& scopes,
60 const scoped_refptr<OAuth2TokenServiceRequest::TokenServiceProvider>& 60 const scoped_refptr<OAuth2TokenServiceRequest::TokenServiceProvider>&
61 token_service_provider, 61 token_service_provider,
62 const std::string& store_birthday, 62 const std::string& store_birthday,
63 ModelType model_type) 63 ModelType model_type)
64 : OAuth2TokenService::Consumer("attachment-downloader-impl"), 64 : OAuth2TokenService::Consumer("attachment-downloader-impl"),
65 sync_service_url_(sync_service_url), 65 sync_service_url_(sync_service_url),
66 url_request_context_getter_(url_request_context_getter), 66 url_request_context_getter_(url_request_context_getter),
67 account_id_(account_id), 67 account_id_(account_id),
68 oauth2_scopes_(scopes), 68 oauth2_scopes_(scopes),
69 token_service_provider_(token_service_provider), 69 token_service_provider_(token_service_provider),
70 raw_store_birthday_(store_birthday), 70 raw_store_birthday_(store_birthday),
71 model_type_(model_type) { 71 model_type_(model_type) {
72 DCHECK(url_request_context_getter_.get()); 72 DCHECK(url_request_context_getter_.get());
73 DCHECK(!account_id.empty()); 73 DCHECK(!account_id.empty());
74 DCHECK(!scopes.empty()); 74 DCHECK(!scopes.empty());
75 DCHECK(token_service_provider_.get()); 75 DCHECK(token_service_provider_.get());
76 DCHECK(!raw_store_birthday_.empty()); 76 DCHECK(!raw_store_birthday_.empty());
77 } 77 }
78 78
79 AttachmentDownloaderImpl::~AttachmentDownloaderImpl() { 79 AttachmentDownloaderImpl::~AttachmentDownloaderImpl() {}
80 }
81 80
82 void AttachmentDownloaderImpl::DownloadAttachment( 81 void AttachmentDownloaderImpl::DownloadAttachment(
83 const AttachmentId& attachment_id, 82 const AttachmentId& attachment_id,
84 const DownloadCallback& callback) { 83 const DownloadCallback& callback) {
85 DCHECK(CalledOnValidThread()); 84 DCHECK(CalledOnValidThread());
86 85
87 AttachmentUrl url = AttachmentUploaderImpl::GetURLForAttachmentId( 86 AttachmentUrl url = AttachmentUploaderImpl::GetURLForAttachmentId(
88 sync_service_url_, attachment_id).spec(); 87 sync_service_url_, attachment_id)
88 .spec();
89 89
90 StateMap::iterator iter = state_map_.find(url); 90 StateMap::iterator iter = state_map_.find(url);
91 DownloadState* download_state = 91 DownloadState* download_state =
92 iter != state_map_.end() ? iter->second.get() : nullptr; 92 iter != state_map_.end() ? iter->second.get() : nullptr;
93 if (!download_state) { 93 if (!download_state) {
94 // There is no request started for this attachment id. Let's create 94 // There is no request started for this attachment id. Let's create
95 // DownloadState and request access token for it. 95 // DownloadState and request access token for it.
96 std::unique_ptr<DownloadState> new_download_state( 96 std::unique_ptr<DownloadState> new_download_state(
97 new DownloadState(attachment_id, url)); 97 new DownloadState(attachment_id, url));
98 download_state = new_download_state.get(); 98 download_state = new_download_state.get();
99 state_map_[url] = std::move(new_download_state); 99 state_map_[url] = std::move(new_download_state);
100 RequestAccessToken(download_state); 100 RequestAccessToken(download_state);
101 } 101 }
102 DCHECK(download_state->attachment_id == attachment_id); 102 DCHECK(download_state->attachment_id == attachment_id);
103 download_state->user_callbacks.push_back(callback); 103 download_state->user_callbacks.push_back(callback);
104 } 104 }
105 105
106 void AttachmentDownloaderImpl::OnGetTokenSuccess( 106 void AttachmentDownloaderImpl::OnGetTokenSuccess(
107 const OAuth2TokenService::Request* request, 107 const OAuth2TokenService::Request* request,
108 const std::string& access_token, 108 const std::string& access_token,
109 const base::Time& expiration_time) { 109 const base::Time& expiration_time) {
110 DCHECK(CalledOnValidThread()); 110 DCHECK(CalledOnValidThread());
111 DCHECK(request == access_token_request_.get()); 111 DCHECK(request == access_token_request_.get());
112 access_token_request_.reset(); 112 access_token_request_.reset();
113 StateList::const_iterator iter; 113 StateList::const_iterator iter;
114 // Start downloads for all download requests waiting for access token. 114 // Start downloads for all download requests waiting for access token.
115 for (iter = requests_waiting_for_access_token_.begin(); 115 for (iter = requests_waiting_for_access_token_.begin();
116 iter != requests_waiting_for_access_token_.end(); 116 iter != requests_waiting_for_access_token_.end(); ++iter) {
117 ++iter) {
118 DownloadState* download_state = *iter; 117 DownloadState* download_state = *iter;
119 download_state->access_token = access_token; 118 download_state->access_token = access_token;
120 download_state->url_fetcher = 119 download_state->url_fetcher =
121 CreateFetcher(download_state->attachment_url, access_token); 120 CreateFetcher(download_state->attachment_url, access_token);
122 download_state->start_time = base::TimeTicks::Now(); 121 download_state->start_time = base::TimeTicks::Now();
123 download_state->url_fetcher->Start(); 122 download_state->url_fetcher->Start();
124 } 123 }
125 requests_waiting_for_access_token_.clear(); 124 requests_waiting_for_access_token_.clear();
126 } 125 }
127 126
128 void AttachmentDownloaderImpl::OnGetTokenFailure( 127 void AttachmentDownloaderImpl::OnGetTokenFailure(
129 const OAuth2TokenService::Request* request, 128 const OAuth2TokenService::Request* request,
130 const GoogleServiceAuthError& error) { 129 const GoogleServiceAuthError& error) {
131 DCHECK(CalledOnValidThread()); 130 DCHECK(CalledOnValidThread());
132 DCHECK(request == access_token_request_.get()); 131 DCHECK(request == access_token_request_.get());
133 access_token_request_.reset(); 132 access_token_request_.reset();
134 StateList::const_iterator iter; 133 StateList::const_iterator iter;
135 // Without access token all downloads fail. 134 // Without access token all downloads fail.
136 for (iter = requests_waiting_for_access_token_.begin(); 135 for (iter = requests_waiting_for_access_token_.begin();
137 iter != requests_waiting_for_access_token_.end(); 136 iter != requests_waiting_for_access_token_.end(); ++iter) {
138 ++iter) {
139 DownloadState* download_state = *iter; 137 DownloadState* download_state = *iter;
140 scoped_refptr<base::RefCountedString> null_attachment_data; 138 scoped_refptr<base::RefCountedString> null_attachment_data;
141 ReportResult(*download_state, DOWNLOAD_TRANSIENT_ERROR, 139 ReportResult(*download_state, DOWNLOAD_TRANSIENT_ERROR,
142 null_attachment_data); 140 null_attachment_data);
143 // Don't delete using the URL directly to avoid an access after free error 141 // Don't delete using the URL directly to avoid an access after free error
144 // due to std::unordered_map's implementation. See crbug.com/603275. 142 // due to std::unordered_map's implementation. See crbug.com/603275.
145 auto erase_iter = state_map_.find(download_state->attachment_url); 143 auto erase_iter = state_map_.find(download_state->attachment_url);
146 DCHECK(erase_iter != state_map_.end()); 144 DCHECK(erase_iter != state_map_.end());
147 state_map_.erase(erase_iter); 145 state_map_.erase(erase_iter);
148 } 146 }
(...skipping 10 matching lines...) Expand all
159 DCHECK(iter != state_map_.end()); 157 DCHECK(iter != state_map_.end());
160 const DownloadState& download_state = *iter->second; 158 const DownloadState& download_state = *iter->second;
161 DCHECK(source == download_state.url_fetcher.get()); 159 DCHECK(source == download_state.url_fetcher.get());
162 160
163 DownloadResult result = DOWNLOAD_TRANSIENT_ERROR; 161 DownloadResult result = DOWNLOAD_TRANSIENT_ERROR;
164 scoped_refptr<base::RefCountedString> attachment_data; 162 scoped_refptr<base::RefCountedString> attachment_data;
165 uint32_t attachment_crc32c = 0; 163 uint32_t attachment_crc32c = 0;
166 164
167 net::URLRequestStatus status = source->GetStatus(); 165 net::URLRequestStatus status = source->GetStatus();
168 const int response_code = source->GetResponseCode(); 166 const int response_code = source->GetResponseCode();
169 UMA_HISTOGRAM_SPARSE_SLOWLY("Sync.Attachments.DownloadResponseCode", 167 UMA_HISTOGRAM_SPARSE_SLOWLY(
168 "Sync.Attachments.DownloadResponseCode",
170 status.is_success() ? response_code : status.error()); 169 status.is_success() ? response_code : status.error());
171 if (response_code == net::HTTP_OK) { 170 if (response_code == net::HTTP_OK) {
172 std::string data_as_string; 171 std::string data_as_string;
173 source->GetResponseAsString(&data_as_string); 172 source->GetResponseAsString(&data_as_string);
174 attachment_data = base::RefCountedString::TakeString(&data_as_string); 173 attachment_data = base::RefCountedString::TakeString(&data_as_string);
175 174
176 UMA_HISTOGRAM_LONG_TIMES("Sync.Attachments.DownloadTotalTime", 175 UMA_HISTOGRAM_LONG_TIMES(
176 "Sync.Attachments.DownloadTotalTime",
177 base::TimeTicks::Now() - download_state.start_time); 177 base::TimeTicks::Now() - download_state.start_time);
178 178
179 attachment_crc32c = ComputeCrc32c(attachment_data); 179 attachment_crc32c = ComputeCrc32c(attachment_data);
180 uint32_t crc32c_from_headers = 0; 180 uint32_t crc32c_from_headers = 0;
181 if (ExtractCrc32c(source->GetResponseHeaders(), &crc32c_from_headers) && 181 if (ExtractCrc32c(source->GetResponseHeaders(), &crc32c_from_headers) &&
182 attachment_crc32c != crc32c_from_headers) { 182 attachment_crc32c != crc32c_from_headers) {
183 // Fail download only if there is useful crc32c in header and it doesn't 183 // Fail download only if there is useful crc32c in header and it doesn't
184 // match data. All other cases are fine. When crc32c is not in headers 184 // match data. All other cases are fine. When crc32c is not in headers
185 // locally calculated one will be stored and used for further checks. 185 // locally calculated one will be stored and used for further checks.
186 result = DOWNLOAD_TRANSIENT_ERROR; 186 result = DOWNLOAD_TRANSIENT_ERROR;
187 } else { 187 } else {
188 // If the id's crc32c doesn't match that of the downloaded attachment, 188 // If the id's crc32c doesn't match that of the downloaded attachment,
189 // then we're stuck and retrying is unlikely to help. 189 // then we're stuck and retrying is unlikely to help.
190 if (attachment_crc32c != download_state.attachment_id.GetCrc32c()) { 190 if (attachment_crc32c != download_state.attachment_id.GetCrc32c()) {
191 result = DOWNLOAD_UNSPECIFIED_ERROR; 191 result = DOWNLOAD_UNSPECIFIED_ERROR;
192 } else { 192 } else {
193 result = DOWNLOAD_SUCCESS; 193 result = DOWNLOAD_SUCCESS;
194 } 194 }
195 } 195 }
196 UMA_HISTOGRAM_BOOLEAN("Sync.Attachments.DownloadChecksumResult", 196 UMA_HISTOGRAM_BOOLEAN("Sync.Attachments.DownloadChecksumResult",
197 result == DOWNLOAD_SUCCESS); 197 result == DOWNLOAD_SUCCESS);
198 } else if (response_code == net::HTTP_UNAUTHORIZED) { 198 } else if (response_code == net::HTTP_UNAUTHORIZED) {
199 // Server tells us we've got a bad token so invalidate it. 199 // Server tells us we've got a bad token so invalidate it.
200 OAuth2TokenServiceRequest::InvalidateToken(token_service_provider_.get(), 200 OAuth2TokenServiceRequest::InvalidateToken(token_service_provider_.get(),
201 account_id_, 201 account_id_, oauth2_scopes_,
202 oauth2_scopes_,
203 download_state.access_token); 202 download_state.access_token);
204 // Fail the request, but indicate that it may be successful if retried. 203 // Fail the request, but indicate that it may be successful if retried.
205 result = DOWNLOAD_TRANSIENT_ERROR; 204 result = DOWNLOAD_TRANSIENT_ERROR;
206 } else if (response_code == net::HTTP_FORBIDDEN) { 205 } else if (response_code == net::HTTP_FORBIDDEN) {
207 // User is not allowed to use attachments. Retrying won't help. 206 // User is not allowed to use attachments. Retrying won't help.
208 result = DOWNLOAD_UNSPECIFIED_ERROR; 207 result = DOWNLOAD_UNSPECIFIED_ERROR;
209 } else if (response_code == net::URLFetcher::RESPONSE_CODE_INVALID) { 208 } else if (response_code == net::URLFetcher::RESPONSE_CODE_INVALID) {
210 result = DOWNLOAD_TRANSIENT_ERROR; 209 result = DOWNLOAD_TRANSIENT_ERROR;
211 } 210 }
212 ReportResult(download_state, result, attachment_data); 211 ReportResult(download_state, result, attachment_data);
(...skipping 20 matching lines...) Expand all
233 token_service_provider_.get(), account_id_, oauth2_scopes_, this); 232 token_service_provider_.get(), account_id_, oauth2_scopes_, this);
234 } 233 }
235 } 234 }
236 235
237 void AttachmentDownloaderImpl::ReportResult( 236 void AttachmentDownloaderImpl::ReportResult(
238 const DownloadState& download_state, 237 const DownloadState& download_state,
239 const DownloadResult& result, 238 const DownloadResult& result,
240 const scoped_refptr<base::RefCountedString>& attachment_data) { 239 const scoped_refptr<base::RefCountedString>& attachment_data) {
241 std::vector<DownloadCallback>::const_iterator iter; 240 std::vector<DownloadCallback>::const_iterator iter;
242 for (iter = download_state.user_callbacks.begin(); 241 for (iter = download_state.user_callbacks.begin();
243 iter != download_state.user_callbacks.end(); 242 iter != download_state.user_callbacks.end(); ++iter) {
244 ++iter) {
245 std::unique_ptr<Attachment> attachment; 243 std::unique_ptr<Attachment> attachment;
246 if (result == DOWNLOAD_SUCCESS) { 244 if (result == DOWNLOAD_SUCCESS) {
247 attachment.reset(new Attachment(Attachment::CreateFromParts( 245 attachment.reset(new Attachment(Attachment::CreateFromParts(
248 download_state.attachment_id, attachment_data))); 246 download_state.attachment_id, attachment_data)));
249 } 247 }
250 248
251 base::ThreadTaskRunnerHandle::Get()->PostTask( 249 base::ThreadTaskRunnerHandle::Get()->PostTask(
252 FROM_HERE, base::Bind(*iter, result, base::Passed(&attachment))); 250 FROM_HERE, base::Bind(*iter, result, base::Passed(&attachment)));
253 } 251 }
254 } 252 }
255 253
256 bool AttachmentDownloaderImpl::ExtractCrc32c( 254 bool AttachmentDownloaderImpl::ExtractCrc32c(
257 const net::HttpResponseHeaders* headers, 255 const net::HttpResponseHeaders* headers,
258 uint32_t* crc32c) { 256 uint32_t* crc32c) {
259 DCHECK(crc32c); 257 DCHECK(crc32c);
260 if (!headers) { 258 if (!headers) {
261 return false; 259 return false;
262 } 260 }
263 261
264 std::string crc32c_encoded; 262 std::string crc32c_encoded;
265 std::string header_value; 263 std::string header_value;
266 size_t iter = 0; 264 size_t iter = 0;
267 // Iterate over all matching headers. 265 // Iterate over all matching headers.
268 while (headers->EnumerateHeader(&iter, "x-goog-hash", &header_value)) { 266 while (headers->EnumerateHeader(&iter, "x-goog-hash", &header_value)) {
269 // Because EnumerateHeader is smart about list values, header_value will 267 // Because EnumerateHeader is smart about list values, header_value will
270 // either be empty or a single name=value pair. 268 // either be empty or a single name=value pair.
271 net::HttpUtil::NameValuePairsIterator pair_iter( 269 net::HttpUtil::NameValuePairsIterator pair_iter(header_value.begin(),
272 header_value.begin(), header_value.end(), ','); 270 header_value.end(), ',');
273 if (pair_iter.GetNext()) { 271 if (pair_iter.GetNext()) {
274 if (pair_iter.name() == "crc32c") { 272 if (pair_iter.name() == "crc32c") {
275 crc32c_encoded = pair_iter.value(); 273 crc32c_encoded = pair_iter.value();
276 DCHECK(!pair_iter.GetNext()); 274 DCHECK(!pair_iter.GetNext());
277 break; 275 break;
278 } 276 }
279 } 277 }
280 } 278 }
281 // Check if header was found 279 // Check if header was found
282 if (crc32c_encoded.empty()) 280 if (crc32c_encoded.empty())
283 return false; 281 return false;
284 std::string crc32c_raw; 282 std::string crc32c_raw;
285 if (!base::Base64Decode(crc32c_encoded, &crc32c_raw)) 283 if (!base::Base64Decode(crc32c_encoded, &crc32c_raw))
286 return false; 284 return false;
287 285
288 if (crc32c_raw.size() != sizeof(*crc32c)) 286 if (crc32c_raw.size() != sizeof(*crc32c))
289 return false; 287 return false;
290 288
291 *crc32c = 289 *crc32c =
292 base::NetToHost32(*reinterpret_cast<const uint32_t*>(crc32c_raw.c_str())); 290 base::NetToHost32(*reinterpret_cast<const uint32_t*>(crc32c_raw.c_str()));
293 return true; 291 return true;
294 } 292 }
295 293
296 } // namespace syncer 294 } // namespace syncer
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698