Chromium Code Reviews| 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 "content/browser/service_worker/service_worker_cache.h" | 5 #include "content/browser/service_worker/service_worker_cache.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/files/file_path.h" | 9 #include "base/files/file_path.h" |
| 10 #include "base/guid.h" | |
| 11 #include "base/message_loop/message_loop_proxy.h" | |
| 12 #include "content/browser/service_worker/service_worker_cache.pb.h" | |
| 13 #include "content/public/browser/browser_thread.h" | |
| 14 #include "net/base/io_buffer.h" | |
| 15 #include "net/base/net_errors.h" | |
| 16 #include "net/disk_cache/disk_cache.h" | |
| 10 #include "net/url_request/url_request_context.h" | 17 #include "net/url_request/url_request_context.h" |
| 18 #include "webkit/browser/blob/blob_data_handle.h" | |
| 11 #include "webkit/browser/blob/blob_storage_context.h" | 19 #include "webkit/browser/blob/blob_storage_context.h" |
| 20 #include "webkit/browser/blob/blob_url_request_job_factory.h" | |
| 12 | 21 |
| 13 namespace content { | 22 namespace content { |
| 14 | 23 |
| 24 namespace { | |
| 25 // The maximum size of an individual cache. Ultimately cache size is controlled | |
| 26 // per-origin. | |
| 27 const int kMaxCacheBytes = 512 * 1024 * 1024; | |
|
michaeln
2014/08/21 01:46:15
there's a bug open about somebody trying to downlo
jkarlin
2014/08/21 18:31:21
We should talk to jsbell about what the appropriat
| |
| 28 | |
| 29 // Buffer size for cache and blob reading/writing. | |
| 30 const int kBufferSize = 1024 * 512; | |
| 31 } | |
| 32 | |
| 33 struct ServiceWorkerCache::ResponseReadContext { | |
| 34 ResponseReadContext(scoped_refptr<net::IOBufferWithSize> buff, | |
| 35 scoped_refptr<webkit_blob::BlobData> blob) | |
| 36 : buffer(buff), blob_data(blob), total_bytes_read(0) {} | |
| 37 | |
| 38 scoped_refptr<net::IOBufferWithSize> buffer; | |
| 39 scoped_refptr<webkit_blob::BlobData> blob_data; | |
| 40 int total_bytes_read; | |
| 41 | |
| 42 DISALLOW_COPY_AND_ASSIGN(ResponseReadContext); | |
| 43 }; | |
| 44 | |
| 45 // Streams data from a blob and writes it to a given disk_cache::Entry. | |
| 46 class ServiceWorkerCache::BlobReader : public net::URLRequest::Delegate { | |
| 47 public: | |
| 48 BlobReader(disk_cache::ScopedEntryPtr entry) | |
| 49 : cache_entry_offset_(0), | |
| 50 buffer_(new net::IOBufferWithSize(kBufferSize)), | |
| 51 weak_ptr_factory_(this) { | |
| 52 DCHECK(entry); | |
| 53 entry_ = entry.Pass(); | |
| 54 } | |
| 55 | |
| 56 void StreamBlobToCache( | |
| 57 net::URLRequestContext* request_context, | |
| 58 scoped_ptr<webkit_blob::BlobDataHandle> blob_data_handle, | |
| 59 const EntryBoolCallback& callback) { | |
| 60 callback_ = callback; | |
| 61 blob_request_ = webkit_blob::BlobProtocolHandler::CreateBlobRequest( | |
| 62 blob_data_handle.Pass(), request_context, this); | |
| 63 blob_request_->Start(); | |
| 64 } | |
| 65 | |
| 66 // net::URLRequest::Delegate overrides for reading blobs. | |
| 67 virtual void OnReceivedRedirect(net::URLRequest* request, | |
| 68 const net::RedirectInfo& redirect_info, | |
| 69 bool* defer_redirect) OVERRIDE { | |
| 70 NOTREACHED(); | |
| 71 } | |
| 72 virtual void OnAuthRequired(net::URLRequest* request, | |
| 73 net::AuthChallengeInfo* auth_info) OVERRIDE { | |
| 74 NOTREACHED(); | |
| 75 } | |
| 76 virtual void OnCertificateRequested( | |
| 77 net::URLRequest* request, | |
| 78 net::SSLCertRequestInfo* cert_request_info) OVERRIDE { | |
| 79 NOTREACHED(); | |
| 80 } | |
| 81 virtual void OnSSLCertificateError(net::URLRequest* request, | |
| 82 const net::SSLInfo& ssl_info, | |
| 83 bool fatal) OVERRIDE { | |
| 84 NOTREACHED(); | |
| 85 } | |
| 86 virtual void OnBeforeNetworkStart(net::URLRequest* request, | |
| 87 bool* defer) OVERRIDE { | |
| 88 NOTREACHED(); | |
| 89 } | |
| 90 | |
| 91 virtual void OnResponseStarted(net::URLRequest* request) OVERRIDE { | |
| 92 if (!request->status().is_success()) { | |
| 93 callback_.Run(entry_.Pass(), false); | |
| 94 return; | |
| 95 } | |
| 96 ReadFromBlob(); | |
| 97 } | |
| 98 | |
| 99 virtual void ReadFromBlob() { | |
| 100 int bytes_read = 0; | |
| 101 bool done = | |
| 102 blob_request_->Read(buffer_.get(), buffer_->size(), &bytes_read); | |
| 103 if (done) | |
| 104 OnReadCompleted(blob_request_.get(), bytes_read); | |
| 105 } | |
| 106 | |
| 107 virtual void OnReadCompleted(net::URLRequest* request, | |
| 108 int bytes_read) OVERRIDE { | |
| 109 if (!request->status().is_success()) { | |
| 110 callback_.Run(entry_.Pass(), false); | |
| 111 return; | |
| 112 } | |
| 113 | |
| 114 if (bytes_read == 0) { | |
| 115 callback_.Run(entry_.Pass(), true); | |
| 116 return; | |
| 117 } | |
| 118 | |
| 119 net::CompletionCallback cache_write_callback = | |
| 120 base::Bind(&BlobReader::DidWriteDataToEntry, | |
| 121 weak_ptr_factory_.GetWeakPtr(), | |
| 122 bytes_read); | |
| 123 | |
| 124 int rv = entry_->WriteData(ServiceWorkerCache::INDEX_RESPONSE_BODY, | |
| 125 cache_entry_offset_, | |
| 126 buffer_, | |
| 127 bytes_read, | |
| 128 cache_write_callback, | |
| 129 true /* truncate */); | |
| 130 if (rv != net::ERR_IO_PENDING) | |
| 131 cache_write_callback.Run(rv); | |
| 132 } | |
| 133 | |
| 134 void DidWriteDataToEntry(int expected_bytes, int rv) { | |
| 135 if (rv != expected_bytes) { | |
|
michaeln
2014/08/21 01:46:15
in this part of the urlrequest contract or just ho
jkarlin
2014/08/21 18:31:20
This is how everybody uses entry->WriteData. Eith
| |
| 136 callback_.Run(entry_.Pass(), false); | |
| 137 return; | |
| 138 } | |
| 139 | |
| 140 cache_entry_offset_ += rv; | |
| 141 ReadFromBlob(); | |
| 142 } | |
| 143 | |
| 144 private: | |
| 145 int cache_entry_offset_; | |
| 146 disk_cache::ScopedEntryPtr entry_; | |
| 147 scoped_ptr<net::URLRequest> blob_request_; | |
| 148 EntryBoolCallback callback_; | |
| 149 scoped_refptr<net::IOBufferWithSize> buffer_; | |
| 150 base::WeakPtrFactory<ServiceWorkerCache::BlobReader> weak_ptr_factory_; | |
| 151 }; | |
| 152 | |
| 15 // static | 153 // static |
| 16 scoped_ptr<ServiceWorkerCache> ServiceWorkerCache::CreateMemoryCache( | 154 scoped_ptr<ServiceWorkerCache> ServiceWorkerCache::CreateMemoryCache( |
| 17 const std::string& name, | 155 const std::string& name, |
| 18 net::URLRequestContext* request_context, | 156 net::URLRequestContext* request_context, |
| 19 base::WeakPtr<webkit_blob::BlobStorageContext> blob_context) { | 157 base::WeakPtr<webkit_blob::BlobStorageContext> blob_context) { |
| 20 return make_scoped_ptr(new ServiceWorkerCache( | 158 return make_scoped_ptr(new ServiceWorkerCache( |
| 21 base::FilePath(), name, request_context, blob_context)); | 159 base::FilePath(), name, request_context, blob_context)); |
| 22 } | 160 } |
| 23 | 161 |
| 24 // static | 162 // static |
| 25 scoped_ptr<ServiceWorkerCache> ServiceWorkerCache::CreatePersistentCache( | 163 scoped_ptr<ServiceWorkerCache> ServiceWorkerCache::CreatePersistentCache( |
| 26 const base::FilePath& path, | 164 const base::FilePath& path, |
| 27 const std::string& name, | 165 const std::string& name, |
| 28 net::URLRequestContext* request_context, | 166 net::URLRequestContext* request_context, |
| 29 base::WeakPtr<webkit_blob::BlobStorageContext> blob_context) { | 167 base::WeakPtr<webkit_blob::BlobStorageContext> blob_context) { |
| 30 return make_scoped_ptr( | 168 return make_scoped_ptr( |
| 31 new ServiceWorkerCache(path, name, request_context, blob_context)); | 169 new ServiceWorkerCache(path, name, request_context, blob_context)); |
| 32 } | 170 } |
| 33 | 171 |
| 34 void ServiceWorkerCache::CreateBackend( | 172 ServiceWorkerCache::~ServiceWorkerCache() { |
| 35 const base::Callback<void(bool)>& callback) { | |
| 36 callback.Run(true); | |
| 37 } | 173 } |
| 38 | 174 |
| 39 base::WeakPtr<ServiceWorkerCache> ServiceWorkerCache::AsWeakPtr() { | 175 base::WeakPtr<ServiceWorkerCache> ServiceWorkerCache::AsWeakPtr() { |
| 40 return weak_ptr_factory_.GetWeakPtr(); | 176 return weak_ptr_factory_.GetWeakPtr(); |
| 41 } | 177 } |
| 42 | 178 |
| 179 void ServiceWorkerCache::CreateBackend(const ErrorCallback& callback) { | |
| 180 DCHECK(!backend_); | |
| 181 | |
| 182 net::CacheType cache_type = | |
| 183 path_.empty() ? net::MEMORY_CACHE : net::DISK_CACHE; | |
|
michaeln
2014/08/21 01:46:15
I think you want to use net::APP_CACHE here instea
jkarlin
2014/08/21 18:31:20
Thanks. Done.
| |
| 184 | |
| 185 scoped_ptr<ScopedBackendPtr> backend_ptr(new ScopedBackendPtr()); | |
| 186 | |
| 187 // Temporary pointer so that backend_ptr can be Pass()'d in Bind below. | |
| 188 ScopedBackendPtr* backend = backend_ptr.get(); | |
| 189 | |
| 190 net::CompletionCallback create_cache_callback = | |
| 191 base::Bind(&ServiceWorkerCache::CreateBackendDidCreate, | |
|
michaeln
2014/08/21 01:46:15
nit: it might be more readable to invoke base::Bin
jkarlin
2014/08/21 18:31:21
Having create_cache_callback let's me both pass it
| |
| 192 weak_ptr_factory_.GetWeakPtr(), | |
| 193 callback, | |
| 194 base::Passed(backend_ptr.Pass())); | |
| 195 | |
| 196 // TODO(jkarlin): Use the cache MessageLoopProxy that ServiceWorkerCacheCore | |
| 197 // has for disk caches. | |
| 198 // TODO(jkarlin): Switch to SimpleCache after debugging why the | |
| 199 // QuickStressBody unittest fails with it. | |
| 200 int rv = disk_cache::CreateCacheBackend( | |
| 201 cache_type, | |
| 202 net::CACHE_BACKEND_BLOCKFILE, | |
| 203 path_, | |
| 204 kMaxCacheBytes, | |
| 205 false, /* force */ | |
| 206 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE).get(), | |
| 207 NULL, | |
| 208 backend, | |
| 209 create_cache_callback); | |
| 210 if (rv != net::ERR_IO_PENDING) | |
| 211 create_cache_callback.Run(rv); | |
| 212 } | |
| 213 | |
| 214 void ServiceWorkerCache::CreateBackendDidCreate( | |
| 215 const ErrorCallback& callback, | |
| 216 scoped_ptr<ScopedBackendPtr> backend_ptr, | |
| 217 int rv) { | |
| 218 if (rv != net::OK) { | |
| 219 callback.Run(ErrorTypeStorage); | |
| 220 return; | |
| 221 } | |
| 222 backend_ = backend_ptr->Pass(); | |
| 223 callback.Run(ErrorTypeOK); | |
| 224 } | |
| 225 | |
| 226 void ServiceWorkerCache::Put(ServiceWorkerFetchRequest* request, | |
|
michaeln
2014/08/21 01:46:15
wassup with ownership of |request| and |response|?
jkarlin
2014/08/21 18:31:20
Owned by the caller. The callback is now guarante
| |
| 227 ServiceWorkerResponse* response, | |
| 228 const ErrorCallback& callback) { | |
| 229 DCHECK(backend_); | |
| 230 | |
| 231 scoped_ptr<disk_cache::Entry*> entry(new disk_cache::Entry*); | |
| 232 | |
| 233 disk_cache::Entry** entry_ptr = entry.get(); | |
| 234 | |
| 235 scoped_ptr<webkit_blob::BlobDataHandle> blob_data_handle; | |
| 236 | |
| 237 if (!response->blob_uuid.empty()) { | |
| 238 if (!blob_storage_context_) { | |
| 239 callback.Run(ErrorTypeStorage); | |
| 240 return; | |
| 241 } | |
| 242 blob_data_handle = | |
| 243 blob_storage_context_->GetBlobDataFromUUID(response->blob_uuid); | |
| 244 if (!blob_data_handle) { | |
| 245 callback.Run(ErrorTypeStorage); | |
| 246 return; | |
| 247 } | |
| 248 } | |
| 249 | |
| 250 net::CompletionCallback create_entry_callback = | |
| 251 base::Bind(&ServiceWorkerCache::PutDidCreateEntry, | |
| 252 weak_ptr_factory_.GetWeakPtr(), | |
| 253 request, | |
| 254 response, | |
| 255 callback, | |
| 256 base::Passed(entry.Pass()), | |
| 257 base::Passed(blob_data_handle.Pass())); | |
| 258 | |
| 259 int rv = backend_->CreateEntry( | |
| 260 request->url.spec(), entry_ptr, create_entry_callback); | |
| 261 | |
| 262 if (rv != net::ERR_IO_PENDING) | |
| 263 create_entry_callback.Run(rv); | |
| 264 } | |
| 265 | |
| 266 void ServiceWorkerCache::Match(ServiceWorkerFetchRequest* request, | |
| 267 const ResponseCallback& callback) { | |
| 268 DCHECK(backend_); | |
| 269 | |
| 270 scoped_ptr<disk_cache::Entry*> entry(new disk_cache::Entry*); | |
| 271 | |
| 272 disk_cache::Entry** entry_ptr = entry.get(); | |
| 273 | |
| 274 net::CompletionCallback open_entry_callback = | |
| 275 base::Bind(&ServiceWorkerCache::MatchDidOpenEntry, | |
| 276 weak_ptr_factory_.GetWeakPtr(), | |
| 277 request, | |
| 278 callback, | |
| 279 base::Passed(entry.Pass())); | |
| 280 | |
| 281 int rv = | |
| 282 backend_->OpenEntry(request->url.spec(), entry_ptr, open_entry_callback); | |
| 283 if (rv != net::ERR_IO_PENDING) | |
| 284 open_entry_callback.Run(rv); | |
| 285 } | |
| 286 | |
| 287 void ServiceWorkerCache::Delete(ServiceWorkerFetchRequest* request, | |
| 288 const ErrorCallback& callback) { | |
| 289 DCHECK(backend_); | |
| 290 | |
| 291 scoped_ptr<disk_cache::Entry*> entry(new disk_cache::Entry*); | |
| 292 | |
| 293 disk_cache::Entry** entry_ptr = entry.get(); | |
| 294 | |
| 295 net::CompletionCallback open_entry_callback = | |
| 296 base::Bind(&ServiceWorkerCache::DeleteDidOpenEntry, | |
| 297 weak_ptr_factory_.GetWeakPtr(), | |
| 298 request, | |
| 299 callback, | |
| 300 base::Passed(entry.Pass())); | |
| 301 | |
| 302 int rv = | |
| 303 backend_->OpenEntry(request->url.spec(), entry_ptr, open_entry_callback); | |
| 304 if (rv != net::ERR_IO_PENDING) | |
| 305 open_entry_callback.Run(rv); | |
| 306 } | |
| 307 | |
| 308 bool ServiceWorkerCache::HasCreatedBackend() const { | |
| 309 return backend_; | |
| 310 } | |
| 311 | |
| 43 ServiceWorkerCache::ServiceWorkerCache( | 312 ServiceWorkerCache::ServiceWorkerCache( |
| 44 const base::FilePath& path, | 313 const base::FilePath& path, |
| 45 const std::string& name, | 314 const std::string& name, |
| 46 net::URLRequestContext* request_context, | 315 net::URLRequestContext* request_context, |
| 47 base::WeakPtr<webkit_blob::BlobStorageContext> blob_context) | 316 base::WeakPtr<webkit_blob::BlobStorageContext> blob_context) |
| 48 : path_(path), | 317 : path_(path), |
| 49 name_(name), | 318 name_(name), |
| 50 request_context_(request_context), | 319 request_context_(request_context), |
| 51 blob_storage_context_(blob_context), | 320 blob_storage_context_(blob_context), |
| 52 id_(0), | 321 id_(0), |
| 53 weak_ptr_factory_(this) { | 322 weak_ptr_factory_(this) { |
| 54 } | 323 } |
| 55 | 324 |
| 56 ServiceWorkerCache::~ServiceWorkerCache() { | 325 void ServiceWorkerCache::MatchDidOpenEntry( |
| 326 ServiceWorkerFetchRequest* request, | |
|
michaeln
2014/08/21 01:46:15
wassup with ownership of 'request'?
jkarlin
2014/08/21 18:31:21
Owned by the caller. The callback is now guarante
| |
| 327 const ResponseCallback& callback, | |
| 328 scoped_ptr<disk_cache::Entry*> entryptr, | |
| 329 int rv) { | |
| 330 if (rv != net::OK) { | |
| 331 callback.Run(ErrorTypeNotFound, | |
| 332 scoped_ptr<ServiceWorkerResponse>(), | |
| 333 scoped_ptr<webkit_blob::BlobDataHandle>()); | |
| 334 return; | |
| 335 } | |
| 336 | |
| 337 DCHECK(entryptr); | |
| 338 disk_cache::ScopedEntryPtr entry(*entryptr); | |
| 339 | |
| 340 scoped_refptr<net::IOBufferWithSize> buffer( | |
| 341 new net::IOBufferWithSize(entry->GetDataSize(INDEX_HEADERS))); | |
| 342 | |
| 343 // Copy the entry pointer before passing it in base::Bind. | |
| 344 disk_cache::Entry* tmp_entry_ptr = entry.get(); | |
| 345 | |
| 346 net::CompletionCallback read_header_callback = | |
| 347 base::Bind(&ServiceWorkerCache::MatchDidReadHeaderData, | |
| 348 weak_ptr_factory_.GetWeakPtr(), | |
| 349 request, | |
| 350 callback, | |
| 351 base::Passed(entry.Pass()), | |
| 352 buffer); | |
| 353 | |
| 354 int read_rv = tmp_entry_ptr->ReadData( | |
| 355 INDEX_HEADERS, 0, buffer.get(), buffer->size(), read_header_callback); | |
| 356 | |
| 357 if (read_rv != net::ERR_IO_PENDING) | |
| 358 read_header_callback.Run(read_rv); | |
| 359 } | |
| 360 | |
| 361 void ServiceWorkerCache::MatchDidReadHeaderData( | |
| 362 ServiceWorkerFetchRequest* request, | |
| 363 const ResponseCallback& callback, | |
| 364 disk_cache::ScopedEntryPtr entry, | |
| 365 const scoped_refptr<net::IOBufferWithSize>& buffer, | |
| 366 int rv) { | |
| 367 if (rv != buffer->size()) { | |
| 368 callback.Run(ErrorTypeStorage, | |
| 369 scoped_ptr<ServiceWorkerResponse>(), | |
| 370 scoped_ptr<webkit_blob::BlobDataHandle>()); | |
| 371 | |
| 372 return; | |
| 373 } | |
| 374 | |
| 375 ServiceWorkerRequestResponseHeaders headers; | |
| 376 | |
| 377 if (!headers.ParseFromArray(buffer->data(), buffer->size())) { | |
| 378 callback.Run(ErrorTypeStorage, | |
| 379 scoped_ptr<ServiceWorkerResponse>(), | |
| 380 scoped_ptr<webkit_blob::BlobDataHandle>()); | |
| 381 | |
| 382 return; | |
| 383 } | |
| 384 | |
| 385 scoped_ptr<ServiceWorkerResponse> response( | |
| 386 new ServiceWorkerResponse(request->url, | |
| 387 headers.status_code(), | |
| 388 headers.status_text(), | |
| 389 std::map<std::string, std::string>(), | |
| 390 "")); | |
| 391 | |
| 392 for (int i = 0; i < headers.response_headers_size(); ++i) { | |
| 393 const ServiceWorkerRequestResponseHeaders::HeaderMap header = | |
| 394 headers.response_headers(i); | |
| 395 response->headers.insert(std::make_pair(header.name(), header.value())); | |
| 396 } | |
| 397 | |
| 398 // TODO(jkarlin): Insert vary validation here. | |
| 399 | |
| 400 if (entry->GetDataSize(INDEX_RESPONSE_BODY) == 0) { | |
| 401 callback.Run(ErrorTypeOK, | |
| 402 response.Pass(), | |
| 403 scoped_ptr<webkit_blob::BlobDataHandle>()); | |
| 404 return; | |
| 405 } | |
| 406 | |
| 407 // Stream the response body into a blob. | |
| 408 if (!blob_storage_context_) { | |
| 409 callback.Run(ErrorTypeStorage, | |
| 410 scoped_ptr<ServiceWorkerResponse>(), | |
| 411 scoped_ptr<webkit_blob::BlobDataHandle>()); | |
| 412 | |
| 413 return; | |
| 414 } | |
| 415 | |
| 416 response->blob_uuid = base::GenerateGUID(); | |
| 417 | |
| 418 scoped_refptr<webkit_blob::BlobData> blob_data = | |
| 419 new webkit_blob::BlobData(response->blob_uuid); | |
| 420 scoped_refptr<net::IOBufferWithSize> response_body_buffer( | |
| 421 new net::IOBufferWithSize(kBufferSize)); | |
| 422 | |
| 423 scoped_ptr<ResponseReadContext> read_context( | |
| 424 new ResponseReadContext(response_body_buffer, blob_data)); | |
| 425 | |
| 426 // Copy the entry pointer before passing it in base::Bind. | |
| 427 disk_cache::Entry* tmp_entry_ptr = entry.get(); | |
| 428 | |
| 429 net::CompletionCallback read_callback = | |
| 430 base::Bind(&ServiceWorkerCache::MatchDidReadResponseBodyData, | |
| 431 weak_ptr_factory_.GetWeakPtr(), | |
| 432 request, | |
| 433 callback, | |
| 434 base::Passed(entry.Pass()), | |
| 435 base::Passed(response.Pass()), | |
| 436 base::Passed(read_context.Pass())); | |
| 437 | |
| 438 int read_rv = tmp_entry_ptr->ReadData(INDEX_RESPONSE_BODY, | |
| 439 0, | |
| 440 response_body_buffer.get(), | |
| 441 response_body_buffer->size(), | |
| 442 read_callback); | |
| 443 | |
| 444 if (read_rv != net::ERR_IO_PENDING) | |
| 445 read_callback.Run(read_rv); | |
| 446 } | |
| 447 | |
| 448 void ServiceWorkerCache::MatchDidReadResponseBodyData( | |
| 449 ServiceWorkerFetchRequest* request, | |
| 450 const ResponseCallback& callback, | |
| 451 disk_cache::ScopedEntryPtr entry, | |
| 452 scoped_ptr<ServiceWorkerResponse> response, | |
| 453 scoped_ptr<ResponseReadContext> response_context, | |
| 454 int rv) { | |
| 455 if (rv < 0) { | |
| 456 callback.Run(ErrorTypeStorage, | |
| 457 scoped_ptr<ServiceWorkerResponse>(), | |
| 458 scoped_ptr<webkit_blob::BlobDataHandle>()); | |
| 459 return; | |
| 460 } | |
| 461 | |
| 462 if (rv == 0) { | |
| 463 MatchDoneWithBody( | |
| 464 request, callback, response.Pass(), response_context.Pass()); | |
| 465 return; | |
| 466 } | |
| 467 | |
| 468 // TODO(jkarlin): This copying of the the entire cache response into memory is | |
|
michaeln
2014/08/21 01:46:15
It's really hard to say this looks good. Every cal
jkarlin
2014/08/21 18:31:21
Yes, this optimization needs to happen. But we ne
| |
| 469 // awful. Create a new interface around SimpleCache that provides access the | |
| 470 // data directly from the file. See bug http://crbug.com/403493. | |
| 471 response_context->blob_data->AppendData(response_context->buffer->data(), rv); | |
| 472 response_context->total_bytes_read += rv; | |
| 473 int total_bytes_read = response_context->total_bytes_read; | |
| 474 | |
| 475 // Grab some pointers before passing them in bind. | |
| 476 net::IOBufferWithSize* buffer = response_context->buffer; | |
| 477 disk_cache::Entry* tmp_entry_ptr = entry.get(); | |
| 478 | |
| 479 net::CompletionCallback read_callback = | |
| 480 base::Bind(&ServiceWorkerCache::MatchDidReadResponseBodyData, | |
| 481 weak_ptr_factory_.GetWeakPtr(), | |
| 482 request, | |
| 483 callback, | |
| 484 base::Passed(entry.Pass()), | |
| 485 base::Passed(response.Pass()), | |
| 486 base::Passed(response_context.Pass())); | |
| 487 | |
| 488 int read_rv = tmp_entry_ptr->ReadData(INDEX_RESPONSE_BODY, | |
| 489 total_bytes_read, | |
| 490 buffer, | |
| 491 buffer->size(), | |
| 492 read_callback); | |
| 493 | |
| 494 if (read_rv != net::ERR_IO_PENDING) | |
| 495 read_callback.Run(read_rv); | |
| 496 } | |
| 497 | |
| 498 void ServiceWorkerCache::MatchDoneWithBody( | |
| 499 ServiceWorkerFetchRequest* request, | |
| 500 const ResponseCallback& callback, | |
| 501 scoped_ptr<ServiceWorkerResponse> response, | |
| 502 scoped_ptr<ResponseReadContext> response_context) { | |
| 503 if (!blob_storage_context_) { | |
| 504 callback.Run(ErrorTypeStorage, | |
| 505 scoped_ptr<ServiceWorkerResponse>(), | |
| 506 scoped_ptr<webkit_blob::BlobDataHandle>()); | |
| 507 return; | |
| 508 } | |
| 509 | |
| 510 scoped_ptr<webkit_blob::BlobDataHandle> blob_data_handle( | |
| 511 blob_storage_context_->AddFinishedBlob( | |
| 512 response_context->blob_data.get())); | |
| 513 | |
| 514 callback.Run(ErrorTypeOK, response.Pass(), blob_data_handle.Pass()); | |
| 515 } | |
| 516 | |
| 517 void ServiceWorkerCache::PutDidCreateEntry( | |
| 518 ServiceWorkerFetchRequest* request, | |
| 519 ServiceWorkerResponse* response, | |
| 520 const ErrorCallback& callback, | |
| 521 scoped_ptr<disk_cache::Entry*> entryptr, | |
| 522 scoped_ptr<webkit_blob::BlobDataHandle> blob_data_handle, | |
| 523 int rv) { | |
| 524 if (rv != net::OK) { | |
| 525 callback.Run(ErrorTypeExists); | |
| 526 return; | |
| 527 } | |
| 528 | |
| 529 DCHECK(entryptr); | |
| 530 disk_cache::ScopedEntryPtr entry(*entryptr); | |
| 531 | |
| 532 ServiceWorkerRequestResponseHeaders headers; | |
| 533 headers.set_method(request->method); | |
| 534 | |
| 535 headers.set_status_code(response->status_code); | |
| 536 headers.set_status_text(response->status_text); | |
| 537 for (std::map<std::string, std::string>::const_iterator it = | |
| 538 request->headers.begin(); | |
| 539 it != request->headers.end(); | |
| 540 ++it) { | |
| 541 ServiceWorkerRequestResponseHeaders::HeaderMap* header_map = | |
| 542 headers.add_request_headers(); | |
| 543 header_map->set_name(it->first); | |
| 544 header_map->set_value(it->second); | |
| 545 } | |
| 546 | |
| 547 for (std::map<std::string, std::string>::const_iterator it = | |
| 548 response->headers.begin(); | |
| 549 it != response->headers.end(); | |
| 550 ++it) { | |
| 551 ServiceWorkerRequestResponseHeaders::HeaderMap* header_map = | |
| 552 headers.add_response_headers(); | |
| 553 header_map->set_name(it->first); | |
| 554 header_map->set_value(it->second); | |
| 555 } | |
| 556 | |
| 557 scoped_ptr<std::string> serialized(new std::string()); | |
| 558 if (!headers.SerializeToString(serialized.get())) { | |
| 559 callback.Run(ErrorTypeStorage); | |
| 560 return; | |
| 561 } | |
| 562 | |
| 563 scoped_refptr<net::StringIOBuffer> buffer( | |
| 564 new net::StringIOBuffer(serialized.Pass())); | |
| 565 | |
| 566 // Get a temporary copy of the entry pointer before passing it in base::Bind. | |
| 567 disk_cache::Entry* tmp_entry_ptr = entry.get(); | |
| 568 | |
| 569 net::CompletionCallback write_headers_callback = | |
| 570 base::Bind(&ServiceWorkerCache::PutDidWriteHeaders, | |
| 571 weak_ptr_factory_.GetWeakPtr(), | |
| 572 response, | |
| 573 callback, | |
| 574 base::Passed(entry.Pass()), | |
| 575 base::Passed(blob_data_handle.Pass()), | |
| 576 buffer->size()); | |
| 577 | |
| 578 rv = tmp_entry_ptr->WriteData(INDEX_HEADERS, | |
| 579 0 /* offset */, | |
| 580 buffer, | |
| 581 buffer->size(), | |
| 582 write_headers_callback, | |
| 583 true /* truncate */); | |
| 584 | |
| 585 if (rv != net::ERR_IO_PENDING) | |
| 586 write_headers_callback.Run(rv); | |
| 587 } | |
| 588 | |
| 589 void ServiceWorkerCache::PutDidWriteHeaders( | |
| 590 ServiceWorkerResponse* response, | |
| 591 const ErrorCallback& callback, | |
| 592 disk_cache::ScopedEntryPtr entry, | |
| 593 scoped_ptr<webkit_blob::BlobDataHandle> blob_data_handle, | |
| 594 int expected_bytes, | |
| 595 int rv) { | |
| 596 if (rv != expected_bytes) { | |
| 597 entry->Doom(); | |
| 598 callback.Run(ErrorTypeStorage); | |
| 599 return; | |
| 600 } | |
| 601 | |
| 602 // The metadata is written, now for the response content. The data is streamed | |
| 603 // from the blob into the cache entry. | |
| 604 | |
| 605 if (response->blob_uuid.empty()) { | |
| 606 callback.Run(ErrorTypeOK); | |
| 607 return; | |
| 608 } | |
| 609 | |
| 610 DCHECK(blob_data_handle); | |
| 611 | |
| 612 scoped_ptr<BlobReader> reader(new BlobReader(entry.Pass())); | |
| 613 BlobReader* reader_ptr = reader.get(); | |
| 614 | |
| 615 reader_ptr->StreamBlobToCache( | |
| 616 request_context_, | |
| 617 blob_data_handle.Pass(), | |
| 618 base::Bind(&ServiceWorkerCache::PutDidWriteBlobToCache, | |
| 619 weak_ptr_factory_.GetWeakPtr(), | |
| 620 callback, | |
| 621 base::Passed(reader.Pass()))); | |
| 622 } | |
| 623 | |
| 624 void ServiceWorkerCache::PutDidWriteBlobToCache( | |
| 625 const ErrorCallback& callback, | |
| 626 scoped_ptr<BlobReader> blob_reader, | |
| 627 disk_cache::ScopedEntryPtr entry, | |
| 628 bool success) { | |
| 629 if (!success) { | |
| 630 entry->Doom(); | |
| 631 callback.Run(ErrorTypeStorage); | |
| 632 return; | |
| 633 } | |
| 634 | |
| 635 callback.Run(ErrorTypeOK); | |
| 636 } | |
| 637 | |
| 638 void ServiceWorkerCache::DeleteDidOpenEntry( | |
| 639 ServiceWorkerFetchRequest* request, | |
| 640 const ErrorCallback& callback, | |
| 641 scoped_ptr<disk_cache::Entry*> entryptr, | |
| 642 int rv) { | |
| 643 if (rv != net::OK) { | |
| 644 callback.Run(ErrorTypeNotFound); | |
| 645 return; | |
| 646 } | |
| 647 | |
| 648 DCHECK(entryptr); | |
| 649 disk_cache::ScopedEntryPtr entry(*entryptr); | |
| 650 | |
| 651 entry->Doom(); | |
| 652 callback.Run(ErrorTypeOK); | |
| 57 } | 653 } |
| 58 | 654 |
| 59 } // namespace content | 655 } // namespace content |
| OLD | NEW |