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

Side by Side Diff: sync/internal_api/attachments/attachment_downloader_impl.cc

Issue 710073003: Store attachment crc in AttachmentStore (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase Created 6 years, 1 month 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 "sync/internal_api/public/attachments/attachment_downloader_impl.h"
6 6
7 #include "base/base64.h"
7 #include "base/bind.h" 8 #include "base/bind.h"
8 #include "base/message_loop/message_loop.h" 9 #include "base/message_loop/message_loop.h"
10 #include "base/sys_byteorder.h"
9 #include "net/base/load_flags.h" 11 #include "net/base/load_flags.h"
10 #include "net/http/http_response_headers.h" 12 #include "net/http/http_response_headers.h"
11 #include "net/http/http_status_code.h" 13 #include "net/http/http_status_code.h"
12 #include "net/http/http_util.h" 14 #include "net/http/http_util.h"
13 #include "net/url_request/url_fetcher.h" 15 #include "net/url_request/url_fetcher.h"
14 #include "sync/internal_api/public/attachments/attachment_uploader_impl.h" 16 #include "sync/internal_api/public/attachments/attachment_uploader_impl.h"
17 #include "sync/internal_api/public/attachments/attachment_util.h"
15 #include "sync/protocol/sync.pb.h" 18 #include "sync/protocol/sync.pb.h"
16 #include "url/gurl.h" 19 #include "url/gurl.h"
17 20
18 namespace syncer { 21 namespace syncer {
19 22
20 struct AttachmentDownloaderImpl::DownloadState { 23 struct AttachmentDownloaderImpl::DownloadState {
21 public: 24 public:
22 DownloadState(const AttachmentId& attachment_id, 25 DownloadState(const AttachmentId& attachment_id,
23 const AttachmentUrl& attachment_url); 26 const AttachmentUrl& attachment_url);
24 27
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
109 DCHECK(CalledOnValidThread()); 112 DCHECK(CalledOnValidThread());
110 DCHECK(request == access_token_request_.get()); 113 DCHECK(request == access_token_request_.get());
111 access_token_request_.reset(); 114 access_token_request_.reset();
112 StateList::const_iterator iter; 115 StateList::const_iterator iter;
113 // Without access token all downloads fail. 116 // Without access token all downloads fail.
114 for (iter = requests_waiting_for_access_token_.begin(); 117 for (iter = requests_waiting_for_access_token_.begin();
115 iter != requests_waiting_for_access_token_.end(); 118 iter != requests_waiting_for_access_token_.end();
116 ++iter) { 119 ++iter) {
117 DownloadState* download_state = *iter; 120 DownloadState* download_state = *iter;
118 scoped_refptr<base::RefCountedString> null_attachment_data; 121 scoped_refptr<base::RefCountedString> null_attachment_data;
119 ReportResult( 122 ReportResult(*download_state, DOWNLOAD_TRANSIENT_ERROR,
120 *download_state, DOWNLOAD_TRANSIENT_ERROR, null_attachment_data); 123 null_attachment_data, 0);
121 DCHECK(state_map_.find(download_state->attachment_url) != state_map_.end()); 124 DCHECK(state_map_.find(download_state->attachment_url) != state_map_.end());
122 state_map_.erase(download_state->attachment_url); 125 state_map_.erase(download_state->attachment_url);
123 } 126 }
124 requests_waiting_for_access_token_.clear(); 127 requests_waiting_for_access_token_.clear();
125 } 128 }
126 129
127 void AttachmentDownloaderImpl::OnURLFetchComplete( 130 void AttachmentDownloaderImpl::OnURLFetchComplete(
128 const net::URLFetcher* source) { 131 const net::URLFetcher* source) {
129 DCHECK(CalledOnValidThread()); 132 DCHECK(CalledOnValidThread());
130 133
131 // Find DownloadState by url. 134 // Find DownloadState by url.
132 AttachmentUrl url = source->GetOriginalURL().spec(); 135 AttachmentUrl url = source->GetOriginalURL().spec();
133 StateMap::iterator iter = state_map_.find(url); 136 StateMap::iterator iter = state_map_.find(url);
134 DCHECK(iter != state_map_.end()); 137 DCHECK(iter != state_map_.end());
135 const DownloadState& download_state = *iter->second; 138 const DownloadState& download_state = *iter->second;
136 DCHECK(source == download_state.url_fetcher.get()); 139 DCHECK(source == download_state.url_fetcher.get());
137 140
138 DownloadResult result = DOWNLOAD_TRANSIENT_ERROR; 141 DownloadResult result = DOWNLOAD_TRANSIENT_ERROR;
139 scoped_refptr<base::RefCountedString> attachment_data; 142 scoped_refptr<base::RefCountedString> attachment_data;
143 uint32_t attachment_crc = 0;
140 144
141 const int response_code = source->GetResponseCode(); 145 const int response_code = source->GetResponseCode();
142 if (response_code == net::HTTP_OK) { 146 if (response_code == net::HTTP_OK) {
143 std::string data_as_string; 147 std::string data_as_string;
144 source->GetResponseAsString(&data_as_string); 148 source->GetResponseAsString(&data_as_string);
145 if (VerifyHashIfPresent(*source, data_as_string)) { 149 attachment_data = base::RefCountedString::TakeString(&data_as_string);
150
151 attachment_crc = ComputeCrc32c(attachment_data);
152 uint32_t crc32c_from_headers = 0;
153 if (ExtractCrc32c(source->GetResponseHeaders(), &crc32c_from_headers) &&
154 attachment_crc != crc32c_from_headers) {
155 // Fail download only if there is useful crc in header and it doesn't
maniscalco 2014/11/11 00:44:54 crc -> crc32c (and elsewhere in this comment)
pavely 2014/11/11 22:27:14 Done.
156 // match data. All other cases are fine. When crc is not in headers
157 // locally calculated one will be stored and used for further checks.
maniscalco 2014/11/11 00:44:54 extra space between be and stored
pavely 2014/11/11 22:27:14 Done.
158 result = DOWNLOAD_TRANSIENT_ERROR;
159 } else {
146 result = DOWNLOAD_SUCCESS; 160 result = DOWNLOAD_SUCCESS;
147 attachment_data = base::RefCountedString::TakeString(&data_as_string);
148 } else {
149 // TODO(maniscalco): Test me!
150 result = DOWNLOAD_TRANSIENT_ERROR;
151 } 161 }
152 } else if (response_code == net::HTTP_UNAUTHORIZED) { 162 } else if (response_code == net::HTTP_UNAUTHORIZED) {
153 // Server tells us we've got a bad token so invalidate it. 163 // Server tells us we've got a bad token so invalidate it.
154 OAuth2TokenServiceRequest::InvalidateToken(token_service_provider_.get(), 164 OAuth2TokenServiceRequest::InvalidateToken(token_service_provider_.get(),
155 account_id_, 165 account_id_,
156 oauth2_scopes_, 166 oauth2_scopes_,
157 download_state.access_token); 167 download_state.access_token);
158 // Fail the request, but indicate that it may be successful if retried. 168 // Fail the request, but indicate that it may be successful if retried.
159 result = DOWNLOAD_TRANSIENT_ERROR; 169 result = DOWNLOAD_TRANSIENT_ERROR;
160 } else if (response_code == net::HTTP_FORBIDDEN) { 170 } else if (response_code == net::HTTP_FORBIDDEN) {
161 // User is not allowed to use attachments. Retrying won't help. 171 // User is not allowed to use attachments. Retrying won't help.
162 result = DOWNLOAD_UNSPECIFIED_ERROR; 172 result = DOWNLOAD_UNSPECIFIED_ERROR;
163 } else if (response_code == net::URLFetcher::RESPONSE_CODE_INVALID) { 173 } else if (response_code == net::URLFetcher::RESPONSE_CODE_INVALID) {
164 result = DOWNLOAD_TRANSIENT_ERROR; 174 result = DOWNLOAD_TRANSIENT_ERROR;
165 } 175 }
166 ReportResult(download_state, result, attachment_data); 176 ReportResult(download_state, result, attachment_data, attachment_crc);
167 state_map_.erase(iter); 177 state_map_.erase(iter);
168 } 178 }
169 179
170 scoped_ptr<net::URLFetcher> AttachmentDownloaderImpl::CreateFetcher( 180 scoped_ptr<net::URLFetcher> AttachmentDownloaderImpl::CreateFetcher(
171 const AttachmentUrl& url, 181 const AttachmentUrl& url,
172 const std::string& access_token) { 182 const std::string& access_token) {
173 scoped_ptr<net::URLFetcher> url_fetcher( 183 scoped_ptr<net::URLFetcher> url_fetcher(
174 net::URLFetcher::Create(GURL(url), net::URLFetcher::GET, this)); 184 net::URLFetcher::Create(GURL(url), net::URLFetcher::GET, this));
175 url_fetcher->SetAutomaticallyRetryOn5xx(false); 185 url_fetcher->SetAutomaticallyRetryOn5xx(false);
176 const std::string auth_header("Authorization: Bearer " + access_token); 186 const std::string auth_header("Authorization: Bearer " + access_token);
(...skipping 13 matching lines...) Expand all
190 // Start access token request if there is no active one. 200 // Start access token request if there is no active one.
191 if (access_token_request_ == NULL) { 201 if (access_token_request_ == NULL) {
192 access_token_request_ = OAuth2TokenServiceRequest::CreateAndStart( 202 access_token_request_ = OAuth2TokenServiceRequest::CreateAndStart(
193 token_service_provider_.get(), account_id_, oauth2_scopes_, this); 203 token_service_provider_.get(), account_id_, oauth2_scopes_, this);
194 } 204 }
195 } 205 }
196 206
197 void AttachmentDownloaderImpl::ReportResult( 207 void AttachmentDownloaderImpl::ReportResult(
198 const DownloadState& download_state, 208 const DownloadState& download_state,
199 const DownloadResult& result, 209 const DownloadResult& result,
200 const scoped_refptr<base::RefCountedString>& attachment_data) { 210 const scoped_refptr<base::RefCountedString>& attachment_data,
211 uint32_t attachment_crc) {
maniscalco 2014/11/11 00:44:54 crc -> crc32c (and elsewhere in this file)
pavely 2014/11/11 22:27:15 Done.
201 std::vector<DownloadCallback>::const_iterator iter; 212 std::vector<DownloadCallback>::const_iterator iter;
202 for (iter = download_state.user_callbacks.begin(); 213 for (iter = download_state.user_callbacks.begin();
203 iter != download_state.user_callbacks.end(); 214 iter != download_state.user_callbacks.end();
204 ++iter) { 215 ++iter) {
205 scoped_ptr<Attachment> attachment; 216 scoped_ptr<Attachment> attachment;
206 if (result == DOWNLOAD_SUCCESS) { 217 if (result == DOWNLOAD_SUCCESS) {
207 attachment.reset(new Attachment(Attachment::CreateWithId( 218 attachment.reset(new Attachment(Attachment::RestoreExisting(
208 download_state.attachment_id, attachment_data))); 219 download_state.attachment_id, attachment_data, attachment_crc)));
209 } 220 }
210 221
211 base::MessageLoop::current()->PostTask( 222 base::MessageLoop::current()->PostTask(
212 FROM_HERE, base::Bind(*iter, result, base::Passed(&attachment))); 223 FROM_HERE, base::Bind(*iter, result, base::Passed(&attachment)));
213 } 224 }
214 } 225 }
215 226
216 bool AttachmentDownloaderImpl::VerifyHashIfPresent(
217 const net::URLFetcher& fetcher,
218 const std::string& data) {
219 const net::HttpResponseHeaders* headers = fetcher.GetResponseHeaders();
220 if (!headers) {
221 // No headers? It passes.
222 return true;
223 }
224
225 std::string value;
226 if (!ExtractCrc32c(*headers, &value)) {
227 // No crc32c? It passes.
228 return true;
229 }
230
231 if (value ==
232 AttachmentUploaderImpl::ComputeCrc32cHash(data.data(), data.size())) {
233 return true;
234 } else {
235 return false;
236 }
237 }
238
239 bool AttachmentDownloaderImpl::ExtractCrc32c( 227 bool AttachmentDownloaderImpl::ExtractCrc32c(
240 const net::HttpResponseHeaders& headers, 228 const net::HttpResponseHeaders* headers,
241 std::string* crc32c) { 229 uint32_t* crc32c) {
242 DCHECK(crc32c); 230 DCHECK(crc32c);
231 if (!headers) {
232 return false;
233 }
234
235 std::string crc32c_encoded;
243 std::string header_value; 236 std::string header_value;
244 void* iter = NULL; 237 void* iter = NULL;
245 // Iterate over all matching headers. 238 // Iterate over all matching headers.
246 while (headers.EnumerateHeader(&iter, "x-goog-hash", &header_value)) { 239 while (headers->EnumerateHeader(&iter, "x-goog-hash", &header_value)) {
247 // Because EnumerateHeader is smart about list values, header_value will 240 // Because EnumerateHeader is smart about list values, header_value will
248 // either be empty or a single name=value pair. 241 // either be empty or a single name=value pair.
249 net::HttpUtil::NameValuePairsIterator pair_iter( 242 net::HttpUtil::NameValuePairsIterator pair_iter(
250 header_value.begin(), header_value.end(), ','); 243 header_value.begin(), header_value.end(), ',');
251 if (pair_iter.GetNext()) { 244 if (pair_iter.GetNext()) {
252 if (pair_iter.name() == "crc32c") { 245 if (pair_iter.name() == "crc32c") {
253 *crc32c = pair_iter.value(); 246 crc32c_encoded = pair_iter.value();
254 DCHECK(!pair_iter.GetNext()); 247 DCHECK(!pair_iter.GetNext());
255 return true; 248 break;
256 } 249 }
257 } 250 }
258 } 251 }
252 // Check if header was found
253 if (crc32c_encoded.empty())
254 return false;
255 std::string crc32c_raw;
256 if (!base::Base64Decode(crc32c_encoded, &crc32c_raw))
257 return false;
259 258
260 return false; 259 if (crc32c_raw.size() != sizeof(*crc32c))
260 return false;
261
262 *crc32c =
263 base::NetToHost32(*reinterpret_cast<const uint32_t*>(crc32c_raw.c_str()));
264 return true;
261 } 265 }
262 266
263 } // namespace syncer 267 } // namespace syncer
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698