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

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

Issue 1315443003: ServiceWorkerWriteToCacheJob: refactor (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: StateMachine -> DoLoop Created 5 years, 3 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "content/browser/service_worker/service_worker_cache_writer.h"
6
7 #include <string>
8
9 #include "content/browser/appcache/appcache_response.h"
10 #include "content/browser/service_worker/service_worker_disk_cache.h"
11 #include "content/browser/service_worker/service_worker_storage.h"
12
13 namespace {
14
15 const size_t kCopyBufferSize = 16 * 1024;
16
17 enum {
18 STATE_START,
19 STATE_READ_HEADERS_FOR_COMPARE,
20 STATE_READ_HEADERS_FOR_COMPARE_DONE,
21 STATE_READ_DATA_FOR_COMPARE,
22 STATE_READ_DATA_FOR_COMPARE_DONE,
23 STATE_READ_HEADERS_FOR_COPY,
24 STATE_READ_HEADERS_FOR_COPY_DONE,
25 STATE_READ_DATA_FOR_COPY,
26 STATE_READ_DATA_FOR_COPY_DONE,
27 STATE_WRITE_HEADERS_FOR_PASSTHROUGH,
28 STATE_WRITE_HEADERS_FOR_PASSTHROUGH_DONE,
29 STATE_WRITE_DATA_FOR_PASSTHROUGH,
30 STATE_WRITE_DATA_FOR_PASSTHROUGH_DONE,
31 STATE_WRITE_HEADERS_FOR_COPY,
32 STATE_WRITE_HEADERS_FOR_COPY_DONE,
33 STATE_WRITE_DATA_FOR_COPY,
34 STATE_WRITE_DATA_FOR_COPY_DONE,
35 STATE_DONE,
36 };
37
38 // Shim class used to turn always-async functions into async-or-result
39 // functions. See the comments below near ReadInfoHelper.
40 class AsyncOnlyCompletionCallbackAdaptor
41 : public base::RefCounted<AsyncOnlyCompletionCallbackAdaptor> {
42 public:
43 AsyncOnlyCompletionCallbackAdaptor(const net::CompletionCallback& callback)
44 : done_(false),
45 async_(false),
46 result_(net::ERR_IO_PENDING),
47 callback_(callback) {}
48
49 void set_async(bool async) { async_ = async; }
50 bool async() { return async_; }
51 bool done() { return done_; }
52 int result() { return result_; }
53
54 void WrappedCallback(int result) {
55 result_ = result;
56 if (async_)
57 callback_.Run(result);
58 else
59 done_ = true;
60 }
61
62 private:
63 friend class base::RefCounted<AsyncOnlyCompletionCallbackAdaptor>;
64 virtual ~AsyncOnlyCompletionCallbackAdaptor() {}
65
66 bool done_;
falken 2015/09/01 08:06:37 done_ seems not used? It's set in WrappedCallback
Elly Fong-Jones 2015/09/01 13:17:47 Good catch. Instead client code uses result() dire
67 bool async_;
68 int result_;
69 net::CompletionCallback callback_;
70 };
71
72 } // namespace
73
74 namespace content {
75
76 int ServiceWorkerCacheWriter::DoLoop(int status) {
77 bool pause = false;
78 do {
79 int next_state = -1;
80 switch (state_) {
81 case STATE_START:
82 status = Start(&next_state, &pause, status);
83 break;
84 case STATE_READ_HEADERS_FOR_COMPARE:
85 status = ReadHeadersForCompare(&next_state, &pause, status);
86 break;
87 case STATE_READ_HEADERS_FOR_COMPARE_DONE:
88 status = ReadHeadersForCompareDone(&next_state, &pause, status);
89 break;
90 case STATE_READ_DATA_FOR_COMPARE:
91 status = ReadDataForCompare(&next_state, &pause, status);
92 break;
93 case STATE_READ_DATA_FOR_COMPARE_DONE:
94 status = ReadDataForCompareDone(&next_state, &pause, status);
95 break;
96 case STATE_READ_HEADERS_FOR_COPY:
97 status = ReadHeadersForCopy(&next_state, &pause, status);
98 break;
99 case STATE_READ_HEADERS_FOR_COPY_DONE:
100 status = ReadHeadersForCopyDone(&next_state, &pause, status);
101 break;
102 case STATE_READ_DATA_FOR_COPY:
103 status = ReadDataForCopy(&next_state, &pause, status);
104 break;
105 case STATE_READ_DATA_FOR_COPY_DONE:
106 status = ReadDataForCopyDone(&next_state, &pause, status);
107 break;
108 case STATE_WRITE_HEADERS_FOR_PASSTHROUGH:
109 status = WriteHeadersForPassthrough(&next_state, &pause, status);
110 break;
111 case STATE_WRITE_HEADERS_FOR_PASSTHROUGH_DONE:
112 status = WriteHeadersForPassthroughDone(&next_state, &pause, status);
113 break;
114 case STATE_WRITE_DATA_FOR_PASSTHROUGH:
115 status = WriteDataForPassthrough(&next_state, &pause, status);
116 break;
117 case STATE_WRITE_DATA_FOR_PASSTHROUGH_DONE:
118 status = WriteDataForPassthroughDone(&next_state, &pause, status);
119 break;
120 case STATE_WRITE_HEADERS_FOR_COPY:
121 status = WriteHeadersForCopy(&next_state, &pause, status);
122 break;
123 case STATE_WRITE_HEADERS_FOR_COPY_DONE:
124 status = WriteHeadersForCopyDone(&next_state, &pause, status);
125 break;
126 case STATE_WRITE_DATA_FOR_COPY:
127 status = WriteDataForCopy(&next_state, &pause, status);
128 break;
129 case STATE_WRITE_DATA_FOR_COPY_DONE:
130 status = WriteDataForCopyDone(&next_state, &pause, status);
131 break;
132 case STATE_DONE:
133 status = Done(&next_state, &pause, status);
134 break;
135 default:
136 next_state = STATE_DONE;
137 break;
138 }
139 state_ = next_state;
140 } while (status >= net::OK && state_ != STATE_DONE && !pause);
141 return status;
142 }
143
144 ServiceWorkerCacheWriter::ServiceWorkerCacheWriter(
145 const ResponseReaderCreator& reader_creator,
146 const ResponseWriterCreator& writer_creator)
147 : state_(STATE_START),
148 reader_creator_(reader_creator),
149 writer_creator_(writer_creator),
150 weak_factory_(this) {}
151
152 ServiceWorkerCacheWriter::~ServiceWorkerCacheWriter() {}
153
154 net::Error ServiceWorkerCacheWriter::MaybeWriteHeaders(
155 HttpResponseInfoIOBuffer* headers,
156 const OnWriteCompleteCallback& callback) {
157 headers_to_write_ = headers;
158 pending_callback_ = callback;
159 DCHECK_EQ(STATE_START, state_);
160 int result = DoLoop(net::OK);
161 return result >= 0 ? net::OK : static_cast<net::Error>(result);
162 }
163
164 net::Error ServiceWorkerCacheWriter::MaybeWriteData(
165 net::IOBuffer* buf,
166 size_t buf_size,
167 const OnWriteCompleteCallback& callback) {
168 data_to_write_ = buf;
169 len_to_write_ = buf_size;
170 pending_callback_ = callback;
171 int result = DoLoop(net::OK);
172 return result >= 0 ? net::OK : static_cast<net::Error>(result);
173 }
174
175 size_t ServiceWorkerCacheWriter::BytesWritten() const {
falken 2015/09/01 08:06:37 nit: better as bytes_written()?
Elly Fong-Jones 2015/09/01 13:17:47 Done.
176 return bytes_written_;
177 }
178
179 int ServiceWorkerCacheWriter::Start(int* next_state, bool* pause, int result) {
180 bytes_written_ = 0;
181 compare_reader_ = reader_creator_.Run();
182 if (compare_reader_.get())
183 *next_state = STATE_READ_HEADERS_FOR_COMPARE;
184 else
185 // No existing reader, just write the headers back directly.
186 *next_state = STATE_WRITE_HEADERS_FOR_PASSTHROUGH;
187 return net::OK;
188 }
189
190 int ServiceWorkerCacheWriter::ReadHeadersForCompare(int* next_state,
191 bool* pause,
192 int result) {
193 DCHECK(headers_to_write_);
194
195 headers_to_read_ = new HttpResponseInfoIOBuffer;
196 *next_state = STATE_READ_HEADERS_FOR_COMPARE_DONE;
197 return ReadInfoHelper(compare_reader_, headers_to_read_.get());
198 }
199
200 int ServiceWorkerCacheWriter::ReadHeadersForCompareDone(int* next_state,
201 bool* pause,
202 int result) {
203 if (result < 0) {
204 *next_state = STATE_DONE;
205 return static_cast<int>(result);
206 }
207 cached_length_ = headers_to_read_->response_data_size;
208 net_length_ = headers_to_write_->response_data_size;
209 bytes_compared_ = 0;
210 *pause = true;
211 *next_state = STATE_READ_DATA_FOR_COMPARE;
212 return net::OK;
213 }
214
215 int ServiceWorkerCacheWriter::ReadDataForCompare(int* next_state,
216 bool* pause,
217 int result) {
218 DCHECK(data_to_write_);
219
220 data_to_read_ = new net::IOBuffer(len_to_write_);
221 len_to_read_ = len_to_write_;
222 *next_state = STATE_READ_DATA_FOR_COMPARE_DONE;
223 compare_offset_ = 0;
224 return ReadDataHelper(compare_reader_, data_to_read_.get(), len_to_read_);
225 }
226
227 int ServiceWorkerCacheWriter::ReadDataForCompareDone(int* next_state,
228 bool* pause,
229 int result) {
230 DCHECK(data_to_read_);
231 DCHECK(data_to_write_);
232 DCHECK_EQ(len_to_read_, len_to_write_);
233 DCHECK_LE(result + compare_offset_, static_cast<size_t>(len_to_write_));
234
235 if (result < 0) {
236 *next_state = STATE_DONE;
237 return result;
238 }
239
240 // Premature EOF while reading the service worker script cache data to
241 // compare. Fail the comparison.
242 if (result == 0) {
243 *next_state = STATE_READ_HEADERS_FOR_COPY;
244 return net::OK;
245 }
246
247 // Compare the data from AppCache to the data from the network.
falken 2015/09/01 08:06:37 AppCache -> the service worker script cache (or ju
Elly Fong-Jones 2015/09/01 13:17:48 Done.
248 if (memcmp(data_to_read_->data(), data_to_write_->data() + compare_offset_,
249 result)) {
250 // Data mismatched. This method already validated that all the bytes through
251 // |bytes_compared_| were identical, so copy the first |bytes_compared_|
252 // over, then start writing network data back after the changed point.
253 //
254 // Note that the state machine does NOT get paused here, since there is
255 // still further work to do before this object is ready to handle another
256 // WriteData call.
257 *next_state = STATE_READ_HEADERS_FOR_COPY;
258 return net::OK;
259 }
260
261 compare_offset_ += result;
262
263 // This is a little bit tricky. It is possible that not enough data was read
264 // to finish comparing the entire block of data from the network (which is
265 // kept in len_to_write_), so this method may need to issue another read and
266 // return to this state.
267 //
268 // Compare isn't complete yet. Issue another read for the remaining data. Note
269 // that this reuses the same IOBuffer.
270 if (compare_offset_ < static_cast<size_t>(len_to_read_)) {
271 *next_state = STATE_READ_DATA_FOR_COMPARE_DONE;
272 return ReadDataHelper(compare_reader_, data_to_read_.get(),
273 len_to_read_ - compare_offset_);
274 }
275
276 // Cached entry is longer than the network entry but the prefix matches. Copy
277 // just the prefix.
278 if (bytes_compared_ + compare_offset_ >= net_length_ &&
279 net_length_ < cached_length_) {
280 *next_state = STATE_READ_HEADERS_FOR_COPY;
281 return net::OK;
282 }
283
284 // bytes_compared_ only gets incremented when a full block is compared, to
285 // avoid having to use only parts of the buffered network data.
286 bytes_compared_ += result;
287 *next_state = STATE_READ_DATA_FOR_COMPARE;
288 *pause = true;
289 return net::OK;
290 }
291
292 int ServiceWorkerCacheWriter::WriteHeadersForPassthrough(int* next_state,
293 bool* pause,
294 int result) {
295 writer_ = writer_creator_.Run();
296 *next_state = STATE_WRITE_HEADERS_FOR_PASSTHROUGH_DONE;
297 return WriteInfoHelper(writer_, headers_to_write_.get());
298 }
299
300 int ServiceWorkerCacheWriter::WriteHeadersForPassthroughDone(int* next_state,
301 bool* pause,
302 int result) {
303 *next_state = STATE_WRITE_DATA_FOR_PASSTHROUGH;
304 *pause = true;
305 return net::OK;
306 }
307
308 int ServiceWorkerCacheWriter::WriteDataForPassthrough(int* next_state,
309 bool* pause,
310 int result) {
311 *next_state = STATE_WRITE_DATA_FOR_PASSTHROUGH_DONE;
312 return WriteDataHelper(writer_, data_to_write_.get(), len_to_write_);
313 }
314
315 int ServiceWorkerCacheWriter::WriteDataForPassthroughDone(int* next_state,
316 bool* pause,
317 int result) {
318 if (result < 0) {
319 *next_state = STATE_DONE;
320 return static_cast<int>(result);
321 }
322 bytes_written_ += result;
323 *next_state = STATE_WRITE_DATA_FOR_PASSTHROUGH;
324 *pause = true;
325 return net::OK;
326 }
327
328 int ServiceWorkerCacheWriter::ReadHeadersForCopy(int* next_state,
329 bool* pause,
330 int result) {
331 bytes_copied_ = 0;
332 copy_reader_ = reader_creator_.Run();
333 headers_to_read_ = new HttpResponseInfoIOBuffer;
334 data_to_copy_ = new net::IOBuffer(kCopyBufferSize);
335 *next_state = STATE_READ_HEADERS_FOR_COPY_DONE;
336 return ReadInfoHelper(copy_reader_, headers_to_read_.get());
337 }
338
339 int ServiceWorkerCacheWriter::ReadHeadersForCopyDone(int* next_state,
340 bool* pause,
341 int result) {
342 if (result < 0) {
343 *next_state = STATE_DONE;
344 return static_cast<int>(result);
345 }
346 *next_state = STATE_WRITE_HEADERS_FOR_COPY;
347 return net::OK;
348 }
349
350 // Write the just-read headers back to the cache.
351 // Note that this method must create |writer_|, since the only paths to this
352 // state never create a writer.
353 // Also note that this *discards* the read headers and replaces them with the
354 // net headers.
355 int ServiceWorkerCacheWriter::WriteHeadersForCopy(int* next_state,
356 bool* pause,
357 int result) {
358 DCHECK(!writer_);
359 writer_ = writer_creator_.Run();
360 *next_state = STATE_WRITE_HEADERS_FOR_COPY_DONE;
361 return WriteInfoHelper(writer_, headers_to_write_.get());
362 }
363
364 int ServiceWorkerCacheWriter::WriteHeadersForCopyDone(int* next_state,
365 bool* pause,
366 int result) {
367 if (result < 0) {
368 *next_state = STATE_DONE;
369 return static_cast<int>(result);
370 }
371 *next_state = STATE_READ_DATA_FOR_COPY;
372 return net::OK;
373 }
374
375 int ServiceWorkerCacheWriter::ReadDataForCopy(int* next_state,
376 bool* pause,
377 int result) {
378 size_t to_read = std::min(kCopyBufferSize, bytes_compared_ - bytes_copied_);
379 // At this point, all compared bytes have been read. Currently
380 // |data_to_write_| and |len_to_write_| hold the chunk of network input that
381 // caused the comparison failure, so those need to be written back and this
382 // object needs to go into passthrough mode.
383 if (to_read == 0) {
384 *next_state = STATE_WRITE_DATA_FOR_PASSTHROUGH;
385 return net::OK;
386 }
387 *next_state = STATE_READ_DATA_FOR_COPY_DONE;
388 return ReadDataHelper(copy_reader_, data_to_copy_.get(), to_read);
389 }
390
391 int ServiceWorkerCacheWriter::ReadDataForCopyDone(int* next_state,
392 bool* pause,
393 int result) {
394 if (result < 0) {
395 *next_state = STATE_DONE;
396 return result;
397 }
398 *next_state = STATE_WRITE_DATA_FOR_COPY;
399 return result;
400 }
401
402 int ServiceWorkerCacheWriter::WriteDataForCopy(int* next_state,
403 bool* pause,
404 int result) {
405 *next_state = STATE_WRITE_DATA_FOR_COPY_DONE;
406 DCHECK_GT(result, 0);
407 return WriteDataHelper(writer_, data_to_copy_.get(), result);
408 }
409
410 int ServiceWorkerCacheWriter::WriteDataForCopyDone(int* next_state,
411 bool* pause,
412 int result) {
413 if (result < 0) {
414 *next_state = STATE_DONE;
415 return result;
416 }
417 bytes_written_ += result;
418 bytes_copied_ += result;
419 *next_state = STATE_READ_DATA_FOR_COPY;
420 return result;
421 }
422
423 int ServiceWorkerCacheWriter::Done(int* next_state, bool* pause, int result) {
424 *next_state = STATE_DONE;
425 return net::OK;
426 }
427
428 // These helpers adapt the AppCache "always use the callback" pattern to the
429 // //net "only use the callback for async" pattern using
430 // AsyncCompletionCallbackAdaptor.
431 //
432 // Specifically, these methods return result codes directly for synchronous
433 // completions, and only run their callback (which is AsyncDoLoop) for
434 // asynchronous completions.
435
436 int ServiceWorkerCacheWriter::ReadInfoHelper(
437 const scoped_ptr<ServiceWorkerResponseReader>& reader,
438 HttpResponseInfoIOBuffer* buf) {
439 net::CompletionCallback run_callback = base::Bind(
440 &ServiceWorkerCacheWriter::AsyncDoLoop, weak_factory_.GetWeakPtr());
441 scoped_refptr<AsyncOnlyCompletionCallbackAdaptor> adaptor(
442 new AsyncOnlyCompletionCallbackAdaptor(run_callback));
443 reader->ReadInfo(
444 buf, base::Bind(&AsyncOnlyCompletionCallbackAdaptor::WrappedCallback,
445 adaptor));
446 adaptor->set_async(true);
447 return adaptor->result();
448 }
449
450 int ServiceWorkerCacheWriter::ReadDataHelper(
451 const scoped_ptr<ServiceWorkerResponseReader>& reader,
452 net::IOBuffer* buf,
453 int buf_len) {
454 net::CompletionCallback run_callback = base::Bind(
455 &ServiceWorkerCacheWriter::AsyncDoLoop, weak_factory_.GetWeakPtr());
456 scoped_refptr<AsyncOnlyCompletionCallbackAdaptor> adaptor(
457 new AsyncOnlyCompletionCallbackAdaptor(run_callback));
458 reader->ReadData(
459 buf, buf_len,
460 base::Bind(&AsyncOnlyCompletionCallbackAdaptor::WrappedCallback,
461 adaptor));
462 adaptor->set_async(true);
463 return adaptor->result();
464 }
465
466 int ServiceWorkerCacheWriter::WriteInfoHelper(
467 const scoped_ptr<ServiceWorkerResponseWriter>& writer,
468 HttpResponseInfoIOBuffer* buf) {
469 net::CompletionCallback run_callback = base::Bind(
470 &ServiceWorkerCacheWriter::AsyncDoLoop, weak_factory_.GetWeakPtr());
471 scoped_refptr<AsyncOnlyCompletionCallbackAdaptor> adaptor(
472 new AsyncOnlyCompletionCallbackAdaptor(run_callback));
473 writer->WriteInfo(
474 buf, base::Bind(&AsyncOnlyCompletionCallbackAdaptor::WrappedCallback,
475 adaptor));
476 adaptor->set_async(true);
477 return adaptor->result();
478 }
479
480 int ServiceWorkerCacheWriter::WriteDataHelper(
481 const scoped_ptr<ServiceWorkerResponseWriter>& writer,
482 net::IOBuffer* buf,
483 int buf_len) {
484 net::CompletionCallback run_callback = base::Bind(
485 &ServiceWorkerCacheWriter::AsyncDoLoop, weak_factory_.GetWeakPtr());
486 scoped_refptr<AsyncOnlyCompletionCallbackAdaptor> adaptor(
487 new AsyncOnlyCompletionCallbackAdaptor(run_callback));
488 writer->WriteData(
489 buf, buf_len,
490 base::Bind(&AsyncOnlyCompletionCallbackAdaptor::WrappedCallback,
491 adaptor));
492 adaptor->set_async(true);
493 return adaptor->result();
494 }
495
496 void ServiceWorkerCacheWriter::AsyncDoLoop(int result) {
497 result = DoLoop(result);
498 // If the result is ERR_IO_PENDING, the pending callback will be run by a
499 // later invocation of AsyncDoLoop.
500 if (result != net::ERR_IO_PENDING) {
501 OnWriteCompleteCallback callback = pending_callback_;
502 pending_callback_.Reset();
503 net::Error error = result >= 0 ? net::OK : static_cast<net::Error>(result);
504 callback.Run(error);
505 }
506 }
507
508 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698