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

Side by Side Diff: content/browser/service_worker/service_worker_cache.cc

Issue 465463002: Initial implementation of ServiceWorkerCache. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@cache2
Patch Set: Fix order of eval error Created 6 years, 4 months 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 "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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698