| 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_uploader_impl.h" | 5 #include "components/sync/core/attachments/attachment_uploader_impl.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 |
| 8 #include <string> | 9 #include <string> |
| 9 #include <utility> | 10 #include <utility> |
| 10 #include <vector> | 11 #include <vector> |
| 11 | 12 |
| 12 #include "base/base64.h" | 13 #include "base/base64.h" |
| 13 #include "base/base64url.h" | 14 #include "base/base64url.h" |
| 14 #include "base/bind.h" | 15 #include "base/bind.h" |
| 15 #include "base/location.h" | 16 #include "base/location.h" |
| 16 #include "base/macros.h" | 17 #include "base/macros.h" |
| 17 #include "base/memory/weak_ptr.h" | 18 #include "base/memory/weak_ptr.h" |
| 18 #include "base/metrics/sparse_histogram.h" | 19 #include "base/metrics/sparse_histogram.h" |
| 19 #include "base/single_thread_task_runner.h" | 20 #include "base/single_thread_task_runner.h" |
| 20 #include "base/strings/string_piece.h" | 21 #include "base/strings/string_piece.h" |
| 21 #include "base/strings/stringprintf.h" | 22 #include "base/strings/stringprintf.h" |
| 22 #include "base/sys_byteorder.h" | 23 #include "base/sys_byteorder.h" |
| 23 #include "base/threading/non_thread_safe.h" | 24 #include "base/threading/non_thread_safe.h" |
| 24 #include "base/threading/thread_task_runner_handle.h" | 25 #include "base/threading/thread_task_runner_handle.h" |
| 26 #include "components/sync/api/attachments/attachment.h" |
| 27 #include "components/sync/protocol/sync.pb.h" |
| 25 #include "google_apis/gaia/gaia_constants.h" | 28 #include "google_apis/gaia/gaia_constants.h" |
| 26 #include "net/base/load_flags.h" | 29 #include "net/base/load_flags.h" |
| 27 #include "net/http/http_status_code.h" | 30 #include "net/http/http_status_code.h" |
| 28 #include "net/url_request/url_fetcher.h" | 31 #include "net/url_request/url_fetcher.h" |
| 29 #include "net/url_request/url_fetcher_delegate.h" | 32 #include "net/url_request/url_fetcher_delegate.h" |
| 30 #include "net/url_request/url_request_status.h" | 33 #include "net/url_request/url_request_status.h" |
| 31 #include "sync/api/attachments/attachment.h" | |
| 32 #include "sync/protocol/sync.pb.h" | |
| 33 | 34 |
| 34 namespace { | 35 namespace { |
| 35 | 36 |
| 36 const char kContentType[] = "application/octet-stream"; | 37 const char kContentType[] = "application/octet-stream"; |
| 37 const char kAttachments[] = "attachments/"; | 38 const char kAttachments[] = "attachments/"; |
| 38 const char kSyncStoreBirthday[] = "X-Sync-Store-Birthday"; | 39 const char kSyncStoreBirthday[] = "X-Sync-Store-Birthday"; |
| 39 const char kSyncDataTypeId[] = "X-Sync-Data-Type-Id"; | 40 const char kSyncDataTypeId[] = "X-Sync-Data-Type-Id"; |
| 40 | 41 |
| 41 } // namespace | 42 } // namespace |
| 42 | 43 |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 148 model_type_(model_type) { | 149 model_type_(model_type) { |
| 149 DCHECK(upload_url_.is_valid()); | 150 DCHECK(upload_url_.is_valid()); |
| 150 DCHECK(url_request_context_getter_.get()); | 151 DCHECK(url_request_context_getter_.get()); |
| 151 DCHECK(!account_id_.empty()); | 152 DCHECK(!account_id_.empty()); |
| 152 DCHECK(!scopes_.empty()); | 153 DCHECK(!scopes_.empty()); |
| 153 DCHECK(token_service_provider_); | 154 DCHECK(token_service_provider_); |
| 154 DCHECK(!raw_store_birthday_.empty()); | 155 DCHECK(!raw_store_birthday_.empty()); |
| 155 GetToken(); | 156 GetToken(); |
| 156 } | 157 } |
| 157 | 158 |
| 158 AttachmentUploaderImpl::UploadState::~UploadState() { | 159 AttachmentUploaderImpl::UploadState::~UploadState() {} |
| 159 } | |
| 160 | 160 |
| 161 bool AttachmentUploaderImpl::UploadState::IsStopped() const { | 161 bool AttachmentUploaderImpl::UploadState::IsStopped() const { |
| 162 DCHECK(CalledOnValidThread()); | 162 DCHECK(CalledOnValidThread()); |
| 163 return is_stopped_; | 163 return is_stopped_; |
| 164 } | 164 } |
| 165 | 165 |
| 166 void AttachmentUploaderImpl::UploadState::AddUserCallback( | 166 void AttachmentUploaderImpl::UploadState::AddUserCallback( |
| 167 const UploadCallback& user_callback) { | 167 const UploadCallback& user_callback) { |
| 168 DCHECK(CalledOnValidThread()); | 168 DCHECK(CalledOnValidThread()); |
| 169 DCHECK(!is_stopped_); | 169 DCHECK(!is_stopped_); |
| 170 user_callbacks_.push_back(user_callback); | 170 user_callbacks_.push_back(user_callback); |
| 171 } | 171 } |
| 172 | 172 |
| 173 const Attachment& AttachmentUploaderImpl::UploadState::GetAttachment() { | 173 const Attachment& AttachmentUploaderImpl::UploadState::GetAttachment() { |
| 174 DCHECK(CalledOnValidThread()); | 174 DCHECK(CalledOnValidThread()); |
| 175 return attachment_; | 175 return attachment_; |
| 176 } | 176 } |
| 177 | 177 |
| 178 void AttachmentUploaderImpl::UploadState::OnURLFetchComplete( | 178 void AttachmentUploaderImpl::UploadState::OnURLFetchComplete( |
| 179 const net::URLFetcher* source) { | 179 const net::URLFetcher* source) { |
| 180 DCHECK(CalledOnValidThread()); | 180 DCHECK(CalledOnValidThread()); |
| 181 if (is_stopped_) { | 181 if (is_stopped_) { |
| 182 return; | 182 return; |
| 183 } | 183 } |
| 184 | 184 |
| 185 UploadResult result = UPLOAD_TRANSIENT_ERROR; | 185 UploadResult result = UPLOAD_TRANSIENT_ERROR; |
| 186 AttachmentId attachment_id = attachment_.GetId(); | 186 AttachmentId attachment_id = attachment_.GetId(); |
| 187 net::URLRequestStatus status = source->GetStatus(); | 187 net::URLRequestStatus status = source->GetStatus(); |
| 188 const int response_code = source->GetResponseCode(); | 188 const int response_code = source->GetResponseCode(); |
| 189 UMA_HISTOGRAM_SPARSE_SLOWLY("Sync.Attachments.UploadResponseCode", | 189 UMA_HISTOGRAM_SPARSE_SLOWLY( |
| 190 "Sync.Attachments.UploadResponseCode", |
| 190 status.is_success() ? response_code : status.error()); | 191 status.is_success() ? response_code : status.error()); |
| 191 if (response_code == net::HTTP_OK) { | 192 if (response_code == net::HTTP_OK) { |
| 192 result = UPLOAD_SUCCESS; | 193 result = UPLOAD_SUCCESS; |
| 193 } else if (response_code == net::HTTP_UNAUTHORIZED) { | 194 } else if (response_code == net::HTTP_UNAUTHORIZED) { |
| 194 // Server tells us we've got a bad token so invalidate it. | 195 // Server tells us we've got a bad token so invalidate it. |
| 195 OAuth2TokenServiceRequest::InvalidateToken( | 196 OAuth2TokenServiceRequest::InvalidateToken( |
| 196 token_service_provider_, account_id_, scopes_, access_token_); | 197 token_service_provider_, account_id_, scopes_, access_token_); |
| 197 // Fail the request, but indicate that it may be successful if retried. | 198 // Fail the request, but indicate that it may be successful if retried. |
| 198 result = UPLOAD_TRANSIENT_ERROR; | 199 result = UPLOAD_TRANSIENT_ERROR; |
| 199 } else if (response_code == net::HTTP_FORBIDDEN) { | 200 } else if (response_code == net::HTTP_FORBIDDEN) { |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 307 const UploadCallback& callback) { | 308 const UploadCallback& callback) { |
| 308 DCHECK(CalledOnValidThread()); | 309 DCHECK(CalledOnValidThread()); |
| 309 const AttachmentId attachment_id = attachment.GetId(); | 310 const AttachmentId attachment_id = attachment.GetId(); |
| 310 const std::string unique_id = attachment_id.GetProto().unique_id(); | 311 const std::string unique_id = attachment_id.GetProto().unique_id(); |
| 311 DCHECK(!unique_id.empty()); | 312 DCHECK(!unique_id.empty()); |
| 312 StateMap::iterator iter = state_map_.find(unique_id); | 313 StateMap::iterator iter = state_map_.find(unique_id); |
| 313 if (iter != state_map_.end()) { | 314 if (iter != state_map_.end()) { |
| 314 // We have an old upload request for this attachment... | 315 // We have an old upload request for this attachment... |
| 315 if (!iter->second->IsStopped()) { | 316 if (!iter->second->IsStopped()) { |
| 316 // "join" to it. | 317 // "join" to it. |
| 317 DCHECK(attachment.GetData() | 318 DCHECK(attachment.GetData()->Equals( |
| 318 ->Equals(iter->second->GetAttachment().GetData())); | 319 iter->second->GetAttachment().GetData())); |
| 319 iter->second->AddUserCallback(callback); | 320 iter->second->AddUserCallback(callback); |
| 320 return; | 321 return; |
| 321 } else { | 322 } else { |
| 322 // It's stopped so we can't use it. Delete it. | 323 // It's stopped so we can't use it. Delete it. |
| 323 state_map_.erase(iter); | 324 state_map_.erase(iter); |
| 324 } | 325 } |
| 325 } | 326 } |
| 326 | 327 |
| 327 const GURL url = GetURLForAttachmentId(sync_service_url_, attachment_id); | 328 const GURL url = GetURLForAttachmentId(sync_service_url_, attachment_id); |
| 328 std::unique_ptr<UploadState> upload_state(new UploadState( | 329 std::unique_ptr<UploadState> upload_state(new UploadState( |
| (...skipping 25 matching lines...) Expand all Loading... |
| 354 // stopped, but before this method was invoked. In that case the UploadState | 355 // stopped, but before this method was invoked. In that case the UploadState |
| 355 // in the map might be a new one. | 356 // in the map might be a new one. |
| 356 if (iter != state_map_.end() && iter->second->IsStopped()) { | 357 if (iter != state_map_.end() && iter->second->IsStopped()) { |
| 357 state_map_.erase(iter); | 358 state_map_.erase(iter); |
| 358 } | 359 } |
| 359 } | 360 } |
| 360 | 361 |
| 361 std::string AttachmentUploaderImpl::FormatCrc32cHash(uint32_t crc32c) { | 362 std::string AttachmentUploaderImpl::FormatCrc32cHash(uint32_t crc32c) { |
| 362 const uint32_t crc32c_big_endian = base::HostToNet32(crc32c); | 363 const uint32_t crc32c_big_endian = base::HostToNet32(crc32c); |
| 363 const base::StringPiece raw(reinterpret_cast<const char*>(&crc32c_big_endian), | 364 const base::StringPiece raw(reinterpret_cast<const char*>(&crc32c_big_endian), |
| 364 sizeof(crc32c_big_endian)); | 365 sizeof(crc32c_big_endian)); |
| 365 std::string encoded; | 366 std::string encoded; |
| 366 base::Base64Encode(raw, &encoded); | 367 base::Base64Encode(raw, &encoded); |
| 367 return encoded; | 368 return encoded; |
| 368 } | 369 } |
| 369 | 370 |
| 370 void AttachmentUploaderImpl::ConfigureURLFetcherCommon( | 371 void AttachmentUploaderImpl::ConfigureURLFetcherCommon( |
| 371 net::URLFetcher* fetcher, | 372 net::URLFetcher* fetcher, |
| 372 const std::string& access_token, | 373 const std::string& access_token, |
| 373 const std::string& raw_store_birthday, | 374 const std::string& raw_store_birthday, |
| 374 ModelType model_type, | 375 ModelType model_type, |
| 375 net::URLRequestContextGetter* request_context_getter) { | 376 net::URLRequestContextGetter* request_context_getter) { |
| 376 DCHECK(request_context_getter); | 377 DCHECK(request_context_getter); |
| 377 DCHECK(fetcher); | 378 DCHECK(fetcher); |
| 378 fetcher->SetAutomaticallyRetryOn5xx(false); | 379 fetcher->SetAutomaticallyRetryOn5xx(false); |
| 379 fetcher->SetRequestContext(request_context_getter); | 380 fetcher->SetRequestContext(request_context_getter); |
| 380 fetcher->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES | | 381 fetcher->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES | |
| 381 net::LOAD_DO_NOT_SEND_COOKIES | | 382 net::LOAD_DO_NOT_SEND_COOKIES | |
| 382 net::LOAD_DISABLE_CACHE); | 383 net::LOAD_DISABLE_CACHE); |
| 383 fetcher->AddExtraRequestHeader(base::StringPrintf( | 384 fetcher->AddExtraRequestHeader(base::StringPrintf( |
| 384 "%s: Bearer %s", net::HttpRequestHeaders::kAuthorization, | 385 "%s: Bearer %s", net::HttpRequestHeaders::kAuthorization, |
| 385 access_token.c_str())); | 386 access_token.c_str())); |
| 386 // Encode the birthday. Birthday is opaque so we assume it could contain | 387 // Encode the birthday. Birthday is opaque so we assume it could contain |
| 387 // anything. Encode it so that it's safe to pass as an HTTP header value. | 388 // anything. Encode it so that it's safe to pass as an HTTP header value. |
| 388 std::string encoded_store_birthday; | 389 std::string encoded_store_birthday; |
| 389 base::Base64UrlEncode( | 390 base::Base64UrlEncode(raw_store_birthday, |
| 390 raw_store_birthday, base::Base64UrlEncodePolicy::OMIT_PADDING, | 391 base::Base64UrlEncodePolicy::OMIT_PADDING, |
| 391 &encoded_store_birthday); | 392 &encoded_store_birthday); |
| 392 fetcher->AddExtraRequestHeader(base::StringPrintf( | 393 fetcher->AddExtraRequestHeader(base::StringPrintf( |
| 393 "%s: %s", kSyncStoreBirthday, encoded_store_birthday.c_str())); | 394 "%s: %s", kSyncStoreBirthday, encoded_store_birthday.c_str())); |
| 394 | 395 |
| 395 // Use field number to pass ModelType because it's stable and we have server | 396 // Use field number to pass ModelType because it's stable and we have server |
| 396 // code to decode it. | 397 // code to decode it. |
| 397 const int field_number = GetSpecificsFieldNumberFromModelType(model_type); | 398 const int field_number = GetSpecificsFieldNumberFromModelType(model_type); |
| 398 fetcher->AddExtraRequestHeader( | 399 fetcher->AddExtraRequestHeader( |
| 399 base::StringPrintf("%s: %d", kSyncDataTypeId, field_number)); | 400 base::StringPrintf("%s: %d", kSyncDataTypeId, field_number)); |
| 400 } | 401 } |
| 401 | 402 |
| 402 } // namespace syncer | 403 } // namespace syncer |
| OLD | NEW |