| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 "services/url_response_disk_cache/url_response_disk_cache_impl.h" | 5 #include "services/url_response_disk_cache/url_response_disk_cache_impl.h" |
| 6 | 6 |
| 7 #include <dirent.h> | 7 #include <dirent.h> |
| 8 #include <fcntl.h> | 8 #include <fcntl.h> |
| 9 #include <sys/types.h> | 9 #include <sys/types.h> |
| 10 | 10 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 28 #include "services/url_response_disk_cache/url_response_disk_cache_entry.mojom.h
" | 28 #include "services/url_response_disk_cache/url_response_disk_cache_entry.mojom.h
" |
| 29 #include "third_party/zlib/google/zip_reader.h" | 29 #include "third_party/zlib/google/zip_reader.h" |
| 30 #include "url/gurl.h" | 30 #include "url/gurl.h" |
| 31 | 31 |
| 32 namespace mojo { | 32 namespace mojo { |
| 33 | 33 |
| 34 namespace { | 34 namespace { |
| 35 | 35 |
| 36 // The current version of the cache. This should only be incremented. When this | 36 // The current version of the cache. This should only be incremented. When this |
| 37 // is incremented, all current cache entries will be invalidated. | 37 // is incremented, all current cache entries will be invalidated. |
| 38 const uint32_t kCurrentVersion = 0; | 38 const uint32_t kCurrentVersion = 1; |
| 39 | 39 |
| 40 // The delay to wait before starting deleting data. This is delayed to not | 40 // The delay to wait before starting deleting data. This is delayed to not |
| 41 // interfere with the shell startup. | 41 // interfere with the shell startup. |
| 42 const uint32_t kTrashDelayInSeconds = 60; | 42 const uint32_t kTrashDelayInSeconds = 60; |
| 43 | 43 |
| 44 // The delay between the time an entry is invalidated and the cache not |
| 45 // returning it anymore. |
| 46 const uint32_t kTimeUntilInvalidationInSeconds = 90; |
| 47 |
| 44 const char kEtagHeader[] = "etag"; | 48 const char kEtagHeader[] = "etag"; |
| 45 | 49 |
| 46 // Create a new identifier for a cache entry. This will be used as an unique | 50 // Create a new identifier for a cache entry. This will be used as an unique |
| 47 // directory name. | 51 // directory name. |
| 48 std::string GetNewIdentifier() { | 52 std::string GetNewIdentifier() { |
| 49 char bytes[32]; | 53 char bytes[32]; |
| 50 crypto::RandBytes(bytes, arraysize(bytes)); | 54 crypto::RandBytes(bytes, arraysize(bytes)); |
| 51 return base::HexEncode(bytes, arraysize(bytes)); | 55 return base::HexEncode(bytes, arraysize(bytes)); |
| 52 } | 56 } |
| 53 | 57 |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 168 GetStagingDirectory().Append(identifier); | 172 GetStagingDirectory().Append(identifier); |
| 169 base::FilePath entry_directory = GetCacheDirectory().Append(identifier); | 173 base::FilePath entry_directory = GetCacheDirectory().Append(identifier); |
| 170 base::FilePath response_body_path = entry_directory.Append(identifier); | 174 base::FilePath response_body_path = entry_directory.Append(identifier); |
| 171 base::FilePath consumer_cache_directory = | 175 base::FilePath consumer_cache_directory = |
| 172 GetConsumerCacheDirectory(entry_directory); | 176 GetConsumerCacheDirectory(entry_directory); |
| 173 | 177 |
| 174 CacheEntryPtr entry = CacheEntry::New(); | 178 CacheEntryPtr entry = CacheEntry::New(); |
| 175 entry->response = response.Pass(); | 179 entry->response = response.Pass(); |
| 176 entry->entry_directory = entry_directory.value(); | 180 entry->entry_directory = entry_directory.value(); |
| 177 entry->response_body_path = response_body_path.value(); | 181 entry->response_body_path = response_body_path.value(); |
| 182 entry->last_invalidation = base::Time::Max().ToInternalValue(); |
| 178 | 183 |
| 179 db->PutNew(request_origin, url, entry.Pass()); | 184 db->PutNew(request_origin, url, entry.Pass()); |
| 180 | 185 |
| 181 if (!base::CreateDirectoryAndGetError(entry_directory, nullptr) || | 186 if (!base::CreateDirectoryAndGetError(entry_directory, nullptr) || |
| 182 !base::CreateDirectoryAndGetError(consumer_cache_directory, nullptr) || | 187 !base::CreateDirectoryAndGetError(consumer_cache_directory, nullptr) || |
| 183 !base::ReplaceFile(staged_response_body_path, response_body_path, | 188 !base::ReplaceFile(staged_response_body_path, response_body_path, |
| 184 nullptr)) { | 189 nullptr)) { |
| 185 MovePathIntoDir(entry_directory, GetStagingDirectory()); | 190 MovePathIntoDir(entry_directory, GetStagingDirectory()); |
| 186 callback.Run(base::FilePath(), base::FilePath()); | 191 callback.Run(base::FilePath(), base::FilePath()); |
| 187 return; | 192 return; |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 237 return false; | 242 return false; |
| 238 std::vector<std::string> response_etags = | 243 std::vector<std::string> response_etags = |
| 239 GetHeaderValues(etag_header_name, response->headers); | 244 GetHeaderValues(etag_header_name, response->headers); |
| 240 if (response_etags.size() == 0) | 245 if (response_etags.size() == 0) |
| 241 return false; | 246 return false; |
| 242 | 247 |
| 243 // Looking for the first etag header. | 248 // Looking for the first etag header. |
| 244 return entry_etags[0] == response_etags[0]; | 249 return entry_etags[0] == response_etags[0]; |
| 245 } | 250 } |
| 246 | 251 |
| 252 void UpdateLastInvalidation(scoped_refptr<URLResponseDiskCacheDB> db, |
| 253 CacheKeyPtr key, |
| 254 const base::Time& time) { |
| 255 CacheEntryPtr entry = db->Get(key.Clone()); |
| 256 entry->last_invalidation = time.ToInternalValue(); |
| 257 db->Put(key.Pass(), entry.Pass()); |
| 258 } |
| 259 |
| 247 void PruneCache(scoped_refptr<URLResponseDiskCacheDB> db, | 260 void PruneCache(scoped_refptr<URLResponseDiskCacheDB> db, |
| 248 const scoped_ptr<URLResponseDiskCacheDB::Iterator>& iterator) { | 261 const scoped_ptr<URLResponseDiskCacheDB::Iterator>& iterator) { |
| 249 CacheKeyPtr last_key; | 262 CacheKeyPtr last_key; |
| 250 CacheKeyPtr key; | 263 CacheKeyPtr key; |
| 251 CacheEntryPtr entry; | 264 CacheEntryPtr entry; |
| 252 while (iterator->HasNext()) { | 265 while (iterator->HasNext()) { |
| 253 iterator->GetNext(&key, &entry); | 266 iterator->GetNext(&key, &entry); |
| 254 if (last_key && last_key->request_origin == key->request_origin && | 267 if (last_key && last_key->request_origin == key->request_origin && |
| 255 last_key->url == key->url) { | 268 last_key->url == key->url) { |
| 256 base::FilePath entry_directory = base::FilePath(entry->entry_directory); | 269 base::FilePath entry_directory = base::FilePath(entry->entry_directory); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 310 scoped_refptr<URLResponseDiskCacheDB> db, | 323 scoped_refptr<URLResponseDiskCacheDB> db, |
| 311 const std::string& remote_application_url, | 324 const std::string& remote_application_url, |
| 312 InterfaceRequest<URLResponseDiskCache> request) | 325 InterfaceRequest<URLResponseDiskCache> request) |
| 313 : task_runner_(task_runner), db_(db), binding_(this, request.Pass()) { | 326 : task_runner_(task_runner), db_(db), binding_(this, request.Pass()) { |
| 314 request_origin_ = GURL(remote_application_url).GetOrigin().spec(); | 327 request_origin_ = GURL(remote_application_url).GetOrigin().spec(); |
| 315 } | 328 } |
| 316 | 329 |
| 317 URLResponseDiskCacheImpl::~URLResponseDiskCacheImpl() { | 330 URLResponseDiskCacheImpl::~URLResponseDiskCacheImpl() { |
| 318 } | 331 } |
| 319 | 332 |
| 333 bool IsInvalidated(const CacheEntryPtr& entry) { |
| 334 if (!entry) |
| 335 return true; |
| 336 return base::Time::Now() - |
| 337 base::Time::FromInternalValue(entry->last_invalidation) > |
| 338 base::TimeDelta::FromSeconds(kTimeUntilInvalidationInSeconds); |
| 339 } |
| 340 |
| 320 void URLResponseDiskCacheImpl::Get(const String& url, | 341 void URLResponseDiskCacheImpl::Get(const String& url, |
| 321 const GetCallback& callback) { | 342 const GetCallback& callback) { |
| 322 CacheEntryPtr entry = db_->GetNewest(request_origin_, CanonicalizeURL(url)); | 343 CacheKeyPtr key; |
| 323 if (!IsCacheEntryValid(entry)) { | 344 CacheEntryPtr entry = |
| 345 db_->GetNewest(request_origin_, CanonicalizeURL(url), &key); |
| 346 if (IsInvalidated(entry) || !IsCacheEntryValid(entry)) { |
| 324 callback.Run(URLResponsePtr(), Array<uint8_t>(), Array<uint8_t>()); | 347 callback.Run(URLResponsePtr(), Array<uint8_t>(), Array<uint8_t>()); |
| 325 return; | 348 return; |
| 326 } | 349 } |
| 327 callback.Run(entry->response.Pass(), | 350 callback.Run(entry->response.Pass(), |
| 328 PathToArray(base::FilePath(entry->response_body_path)), | 351 PathToArray(base::FilePath(entry->response_body_path)), |
| 329 PathToArray(GetConsumerCacheDirectory( | 352 PathToArray(GetConsumerCacheDirectory( |
| 330 base::FilePath(entry->entry_directory)))); | 353 base::FilePath(entry->entry_directory)))); |
| 354 UpdateLastInvalidation(db_, key.Pass(), base::Time::Now()); |
| 355 } |
| 356 |
| 357 void URLResponseDiskCacheImpl::Validate(const String& url) { |
| 358 CacheKeyPtr key; |
| 359 CacheEntryPtr entry = |
| 360 db_->GetNewest(request_origin_, CanonicalizeURL(url), &key); |
| 361 if (entry) |
| 362 UpdateLastInvalidation(db_, key.Pass(), base::Time::Max()); |
| 331 } | 363 } |
| 332 | 364 |
| 333 void URLResponseDiskCacheImpl::Update(URLResponsePtr response) { | 365 void URLResponseDiskCacheImpl::Update(URLResponsePtr response) { |
| 334 UpdateAndGetInternal(response.Pass(), base::Bind(&DoNothing)); | 366 UpdateAndGetInternal(response.Pass(), base::Bind(&DoNothing)); |
| 335 } | 367 } |
| 336 | 368 |
| 337 void URLResponseDiskCacheImpl::UpdateAndGet( | 369 void URLResponseDiskCacheImpl::UpdateAndGet( |
| 338 URLResponsePtr response, | 370 URLResponsePtr response, |
| 339 const UpdateAndGetCallback& callback) { | 371 const UpdateAndGetCallback& callback) { |
| 340 UpdateAndGetInternal(response.Pass(), base::Bind(&RunMojoCallback, callback)); | 372 UpdateAndGetInternal(response.Pass(), base::Bind(&RunMojoCallback, callback)); |
| 341 } | 373 } |
| 342 | 374 |
| 343 void URLResponseDiskCacheImpl::UpdateAndGetExtracted( | 375 void URLResponseDiskCacheImpl::UpdateAndGetExtracted( |
| 344 URLResponsePtr response, | 376 URLResponsePtr response, |
| 345 const UpdateAndGetExtractedCallback& callback) { | 377 const UpdateAndGetExtractedCallback& callback) { |
| 346 if (response->error || | 378 UpdateAndGetInternal( |
| 347 (response->status_code >= 400 && response->status_code < 600)) { | 379 response.Pass(), |
| 348 callback.Run(Array<uint8_t>(), Array<uint8_t>()); | 380 base::Bind(&URLResponseDiskCacheImpl::UpdateAndGetExtractedInternal, |
| 349 return; | 381 base::Unretained(this), |
| 350 } | 382 base::Bind(&RunMojoCallback, callback))); |
| 351 | |
| 352 std::string url = CanonicalizeURL(response->url); | |
| 353 | |
| 354 // Check if the response is cached and valid. If that's the case, returns the | |
| 355 // cached value. | |
| 356 CacheEntryPtr entry = db_->GetNewest(request_origin_, url); | |
| 357 | |
| 358 if (!IsCacheEntryFresh(response, entry)) { | |
| 359 UpdateAndGetInternal( | |
| 360 response.Pass(), | |
| 361 base::Bind(&URLResponseDiskCacheImpl::UpdateAndGetExtractedInternal, | |
| 362 base::Unretained(this), | |
| 363 base::Bind(&RunMojoCallback, callback))); | |
| 364 return; | |
| 365 } | |
| 366 | |
| 367 base::FilePath entry_directory = base::FilePath(entry->entry_directory); | |
| 368 base::FilePath extraction_directory = GetExtractionDirectory(entry_directory); | |
| 369 if (!PathExists(GetExtractionSentinel(entry_directory))) { | |
| 370 UpdateAndGetExtractedInternal(base::Bind(&RunMojoCallback, callback), | |
| 371 base::FilePath(entry->response_body_path), | |
| 372 GetConsumerCacheDirectory(entry_directory)); | |
| 373 return; | |
| 374 } | |
| 375 | |
| 376 callback.Run(PathToArray(extraction_directory), | |
| 377 PathToArray(GetConsumerCacheDirectory(entry_directory))); | |
| 378 } | 383 } |
| 379 | 384 |
| 380 void URLResponseDiskCacheImpl::UpdateAndGetInternal( | 385 void URLResponseDiskCacheImpl::UpdateAndGetInternal( |
| 381 URLResponsePtr response, | 386 URLResponsePtr response, |
| 382 const ResponseFileAndCacheDirCallback& callback) { | 387 const ResponseFileAndCacheDirCallback& callback) { |
| 383 if (response->error || | 388 if (response->error || |
| 384 (response->status_code >= 400 && response->status_code < 600)) { | 389 (response->status_code >= 400 && response->status_code < 600)) { |
| 385 callback.Run(base::FilePath(), base::FilePath()); | 390 callback.Run(base::FilePath(), base::FilePath()); |
| 386 return; | 391 return; |
| 387 } | 392 } |
| 388 | 393 |
| 389 std::string url = CanonicalizeURL(response->url); | 394 std::string url = CanonicalizeURL(response->url); |
| 390 | 395 |
| 391 // Check if the response is cached and valid. If that's the case, returns | 396 // Check if the response is cached and valid. If that's the case, returns |
| 392 // the cached value. | 397 // the cached value. |
| 393 CacheEntryPtr entry = db_->GetNewest(request_origin_, url); | 398 CacheKeyPtr key; |
| 399 CacheEntryPtr entry = db_->GetNewest(request_origin_, url, &key); |
| 394 if (IsCacheEntryFresh(response, entry)) { | 400 if (IsCacheEntryFresh(response, entry)) { |
| 395 callback.Run( | 401 callback.Run( |
| 396 base::FilePath(entry->response_body_path), | 402 base::FilePath(entry->response_body_path), |
| 397 GetConsumerCacheDirectory(base::FilePath(entry->entry_directory))); | 403 GetConsumerCacheDirectory(base::FilePath(entry->entry_directory))); |
| 404 UpdateLastInvalidation(db_, key.Pass(), base::Time::Max()); |
| 398 return; | 405 return; |
| 399 } | 406 } |
| 400 | 407 |
| 401 if (!response->body.is_valid()) { | 408 if (!response->body.is_valid()) { |
| 402 callback.Run(base::FilePath(), base::FilePath()); | 409 callback.Run(base::FilePath(), base::FilePath()); |
| 403 return; | 410 return; |
| 404 } | 411 } |
| 405 | 412 |
| 406 std::string identifier = GetNewIdentifier(); | 413 std::string identifier = GetNewIdentifier(); |
| 407 // The content is copied to the staging directory so that files are not leaked | 414 // The content is copied to the staging directory so that files are not leaked |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 465 return; | 472 return; |
| 466 } | 473 } |
| 467 } | 474 } |
| 468 // We can ignore write error, as it will just force to clear the cache on the | 475 // We can ignore write error, as it will just force to clear the cache on the |
| 469 // next request. | 476 // next request. |
| 470 WriteFile(GetExtractionSentinel(entry_directory), nullptr, 0); | 477 WriteFile(GetExtractionSentinel(entry_directory), nullptr, 0); |
| 471 callback.Run(extraction_directory, consumer_cache_directory); | 478 callback.Run(extraction_directory, consumer_cache_directory); |
| 472 } | 479 } |
| 473 | 480 |
| 474 } // namespace mojo | 481 } // namespace mojo |
| OLD | NEW |