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 |