OLD | NEW |
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 "sync/internal_api/public/attachments/attachment_downloader_impl.h" |
6 | 6 |
7 #include "base/base64.h" | 7 #include "base/base64.h" |
8 #include "base/bind.h" | 8 #include "base/bind.h" |
9 #include "base/message_loop/message_loop.h" | 9 #include "base/message_loop/message_loop.h" |
10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
125 DCHECK(request == access_token_request_.get()); | 125 DCHECK(request == access_token_request_.get()); |
126 access_token_request_.reset(); | 126 access_token_request_.reset(); |
127 StateList::const_iterator iter; | 127 StateList::const_iterator iter; |
128 // Without access token all downloads fail. | 128 // Without access token all downloads fail. |
129 for (iter = requests_waiting_for_access_token_.begin(); | 129 for (iter = requests_waiting_for_access_token_.begin(); |
130 iter != requests_waiting_for_access_token_.end(); | 130 iter != requests_waiting_for_access_token_.end(); |
131 ++iter) { | 131 ++iter) { |
132 DownloadState* download_state = *iter; | 132 DownloadState* download_state = *iter; |
133 scoped_refptr<base::RefCountedString> null_attachment_data; | 133 scoped_refptr<base::RefCountedString> null_attachment_data; |
134 ReportResult(*download_state, DOWNLOAD_TRANSIENT_ERROR, | 134 ReportResult(*download_state, DOWNLOAD_TRANSIENT_ERROR, |
135 null_attachment_data, 0); | 135 null_attachment_data); |
136 DCHECK(state_map_.find(download_state->attachment_url) != state_map_.end()); | 136 DCHECK(state_map_.find(download_state->attachment_url) != state_map_.end()); |
137 state_map_.erase(download_state->attachment_url); | 137 state_map_.erase(download_state->attachment_url); |
138 } | 138 } |
139 requests_waiting_for_access_token_.clear(); | 139 requests_waiting_for_access_token_.clear(); |
140 } | 140 } |
141 | 141 |
142 void AttachmentDownloaderImpl::OnURLFetchComplete( | 142 void AttachmentDownloaderImpl::OnURLFetchComplete( |
143 const net::URLFetcher* source) { | 143 const net::URLFetcher* source) { |
144 DCHECK(CalledOnValidThread()); | 144 DCHECK(CalledOnValidThread()); |
145 | 145 |
(...skipping 22 matching lines...) Expand all Loading... |
168 | 168 |
169 attachment_crc32c = ComputeCrc32c(attachment_data); | 169 attachment_crc32c = ComputeCrc32c(attachment_data); |
170 uint32_t crc32c_from_headers = 0; | 170 uint32_t crc32c_from_headers = 0; |
171 if (ExtractCrc32c(source->GetResponseHeaders(), &crc32c_from_headers) && | 171 if (ExtractCrc32c(source->GetResponseHeaders(), &crc32c_from_headers) && |
172 attachment_crc32c != crc32c_from_headers) { | 172 attachment_crc32c != crc32c_from_headers) { |
173 // Fail download only if there is useful crc32c in header and it doesn't | 173 // Fail download only if there is useful crc32c in header and it doesn't |
174 // match data. All other cases are fine. When crc32c is not in headers | 174 // match data. All other cases are fine. When crc32c is not in headers |
175 // locally calculated one will be stored and used for further checks. | 175 // locally calculated one will be stored and used for further checks. |
176 result = DOWNLOAD_TRANSIENT_ERROR; | 176 result = DOWNLOAD_TRANSIENT_ERROR; |
177 } else { | 177 } else { |
178 result = DOWNLOAD_SUCCESS; | 178 // If the id's crc32c doesn't match that of the downloaded attachment, |
| 179 // then we're stuck and retrying is unlikely to help. |
| 180 if (attachment_crc32c != download_state.attachment_id.GetCrc32c()) { |
| 181 result = DOWNLOAD_UNSPECIFIED_ERROR; |
| 182 } else { |
| 183 result = DOWNLOAD_SUCCESS; |
| 184 } |
179 } | 185 } |
180 UMA_HISTOGRAM_BOOLEAN("Sync.Attachments.DownloadChecksumResult", | 186 UMA_HISTOGRAM_BOOLEAN("Sync.Attachments.DownloadChecksumResult", |
181 result == DOWNLOAD_SUCCESS); | 187 result == DOWNLOAD_SUCCESS); |
182 } else if (response_code == net::HTTP_UNAUTHORIZED) { | 188 } else if (response_code == net::HTTP_UNAUTHORIZED) { |
183 // Server tells us we've got a bad token so invalidate it. | 189 // Server tells us we've got a bad token so invalidate it. |
184 OAuth2TokenServiceRequest::InvalidateToken(token_service_provider_.get(), | 190 OAuth2TokenServiceRequest::InvalidateToken(token_service_provider_.get(), |
185 account_id_, | 191 account_id_, |
186 oauth2_scopes_, | 192 oauth2_scopes_, |
187 download_state.access_token); | 193 download_state.access_token); |
188 // Fail the request, but indicate that it may be successful if retried. | 194 // Fail the request, but indicate that it may be successful if retried. |
189 result = DOWNLOAD_TRANSIENT_ERROR; | 195 result = DOWNLOAD_TRANSIENT_ERROR; |
190 } else if (response_code == net::HTTP_FORBIDDEN) { | 196 } else if (response_code == net::HTTP_FORBIDDEN) { |
191 // User is not allowed to use attachments. Retrying won't help. | 197 // User is not allowed to use attachments. Retrying won't help. |
192 result = DOWNLOAD_UNSPECIFIED_ERROR; | 198 result = DOWNLOAD_UNSPECIFIED_ERROR; |
193 } else if (response_code == net::URLFetcher::RESPONSE_CODE_INVALID) { | 199 } else if (response_code == net::URLFetcher::RESPONSE_CODE_INVALID) { |
194 result = DOWNLOAD_TRANSIENT_ERROR; | 200 result = DOWNLOAD_TRANSIENT_ERROR; |
195 } | 201 } |
196 ReportResult(download_state, result, attachment_data, attachment_crc32c); | 202 ReportResult(download_state, result, attachment_data); |
197 state_map_.erase(iter); | 203 state_map_.erase(iter); |
198 } | 204 } |
199 | 205 |
200 scoped_ptr<net::URLFetcher> AttachmentDownloaderImpl::CreateFetcher( | 206 scoped_ptr<net::URLFetcher> AttachmentDownloaderImpl::CreateFetcher( |
201 const AttachmentUrl& url, | 207 const AttachmentUrl& url, |
202 const std::string& access_token) { | 208 const std::string& access_token) { |
203 scoped_ptr<net::URLFetcher> url_fetcher( | 209 scoped_ptr<net::URLFetcher> url_fetcher( |
204 net::URLFetcher::Create(GURL(url), net::URLFetcher::GET, this)); | 210 net::URLFetcher::Create(GURL(url), net::URLFetcher::GET, this)); |
205 AttachmentUploaderImpl::ConfigureURLFetcherCommon( | 211 AttachmentUploaderImpl::ConfigureURLFetcherCommon( |
206 url_fetcher.get(), access_token, raw_store_birthday_, model_type_, | 212 url_fetcher.get(), access_token, raw_store_birthday_, model_type_, |
207 url_request_context_getter_.get()); | 213 url_request_context_getter_.get()); |
208 return url_fetcher.Pass(); | 214 return url_fetcher.Pass(); |
209 } | 215 } |
210 | 216 |
211 void AttachmentDownloaderImpl::RequestAccessToken( | 217 void AttachmentDownloaderImpl::RequestAccessToken( |
212 DownloadState* download_state) { | 218 DownloadState* download_state) { |
213 requests_waiting_for_access_token_.push_back(download_state); | 219 requests_waiting_for_access_token_.push_back(download_state); |
214 // Start access token request if there is no active one. | 220 // Start access token request if there is no active one. |
215 if (access_token_request_ == NULL) { | 221 if (access_token_request_ == NULL) { |
216 access_token_request_ = OAuth2TokenServiceRequest::CreateAndStart( | 222 access_token_request_ = OAuth2TokenServiceRequest::CreateAndStart( |
217 token_service_provider_.get(), account_id_, oauth2_scopes_, this); | 223 token_service_provider_.get(), account_id_, oauth2_scopes_, this); |
218 } | 224 } |
219 } | 225 } |
220 | 226 |
221 void AttachmentDownloaderImpl::ReportResult( | 227 void AttachmentDownloaderImpl::ReportResult( |
222 const DownloadState& download_state, | 228 const DownloadState& download_state, |
223 const DownloadResult& result, | 229 const DownloadResult& result, |
224 const scoped_refptr<base::RefCountedString>& attachment_data, | 230 const scoped_refptr<base::RefCountedString>& attachment_data) { |
225 uint32_t attachment_crc32c) { | |
226 std::vector<DownloadCallback>::const_iterator iter; | 231 std::vector<DownloadCallback>::const_iterator iter; |
227 for (iter = download_state.user_callbacks.begin(); | 232 for (iter = download_state.user_callbacks.begin(); |
228 iter != download_state.user_callbacks.end(); | 233 iter != download_state.user_callbacks.end(); |
229 ++iter) { | 234 ++iter) { |
230 scoped_ptr<Attachment> attachment; | 235 scoped_ptr<Attachment> attachment; |
231 if (result == DOWNLOAD_SUCCESS) { | 236 if (result == DOWNLOAD_SUCCESS) { |
232 attachment.reset(new Attachment(Attachment::CreateFromParts( | 237 attachment.reset(new Attachment(Attachment::CreateFromParts( |
233 download_state.attachment_id, attachment_data, attachment_crc32c))); | 238 download_state.attachment_id, attachment_data))); |
234 } | 239 } |
235 | 240 |
236 base::MessageLoop::current()->PostTask( | 241 base::MessageLoop::current()->PostTask( |
237 FROM_HERE, base::Bind(*iter, result, base::Passed(&attachment))); | 242 FROM_HERE, base::Bind(*iter, result, base::Passed(&attachment))); |
238 } | 243 } |
239 } | 244 } |
240 | 245 |
241 bool AttachmentDownloaderImpl::ExtractCrc32c( | 246 bool AttachmentDownloaderImpl::ExtractCrc32c( |
242 const net::HttpResponseHeaders* headers, | 247 const net::HttpResponseHeaders* headers, |
243 uint32_t* crc32c) { | 248 uint32_t* crc32c) { |
(...skipping 28 matching lines...) Expand all Loading... |
272 | 277 |
273 if (crc32c_raw.size() != sizeof(*crc32c)) | 278 if (crc32c_raw.size() != sizeof(*crc32c)) |
274 return false; | 279 return false; |
275 | 280 |
276 *crc32c = | 281 *crc32c = |
277 base::NetToHost32(*reinterpret_cast<const uint32_t*>(crc32c_raw.c_str())); | 282 base::NetToHost32(*reinterpret_cast<const uint32_t*>(crc32c_raw.c_str())); |
278 return true; | 283 return true; |
279 } | 284 } |
280 | 285 |
281 } // namespace syncer | 286 } // namespace syncer |
OLD | NEW |