OLD | NEW |
| (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 #ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CACHE_WRITER_H_ | |
6 #define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CACHE_WRITER_H_ | |
7 | |
8 #include <map> | |
9 #include <set> | |
10 | |
11 #include "base/callback.h" | |
12 #include "base/memory/scoped_ptr.h" | |
13 #include "base/memory/weak_ptr.h" | |
14 #include "content/common/content_export.h" | |
15 #include "net/base/io_buffer.h" | |
16 #include "net/base/net_errors.h" | |
17 | |
18 namespace content { | |
19 | |
20 struct HttpResponseInfoIOBuffer; | |
21 class ServiceWorkerCacheWriterCore; | |
22 class ServiceWorkerResponseReader; | |
23 class ServiceWorkerResponseWriter; | |
24 class ServiceWorkerStorage; | |
25 | |
26 // This class is responsible for possibly updating the ServiceWorker script | |
27 // cache for an installed ServiceWorker main script. If there is no existing | |
28 // cache entry, this class always writes supplied data back to the cache; if | |
29 // there is an existing cache entry, this class only writes supplied data back | |
30 // if there is a cache mismatch. | |
31 // | |
32 // Note that writes done by this class cannot be "short" - ie, if they succeed, | |
33 // they always write all the supplied data back. Therefore completions are | |
34 // signalled with net::Error without a count of bytes written. | |
35 // | |
36 // This class's behavior is modelled as a state machine; see the DoLoop function | |
37 // for comments about this. | |
38 class CONTENT_EXPORT ServiceWorkerCacheWriter { | |
39 public: | |
40 using OnWriteCompleteCallback = base::Callback<void(net::Error)>; | |
41 | |
42 // The types for the factory functions passed into the constructor. These are | |
43 // responsible for creating readers from the existing cache entry and writers | |
44 // to the new cache entry when called. These are passed in as factories | |
45 // instead of passing readers and writers in directly to avoid creating | |
46 // writers to entries that won't be updated, and because this class may need | |
47 // multiple readers internally. | |
48 using ResponseReaderCreator = | |
49 base::Callback<scoped_ptr<ServiceWorkerResponseReader>(void)>; | |
50 using ResponseWriterCreator = | |
51 base::Callback<scoped_ptr<ServiceWorkerResponseWriter>(void)>; | |
52 | |
53 // The existing reader may be null, in which case this instance will | |
54 // unconditionally write back data supplied to |MaybeWriteHeaders| and | |
55 // |MaybeWriteData|. | |
56 ServiceWorkerCacheWriter(const ResponseReaderCreator& reader_creator, | |
57 const ResponseWriterCreator& writer_creator); | |
58 | |
59 virtual ~ServiceWorkerCacheWriter(); | |
60 | |
61 // Writes the supplied |headers| back to the cache. Returns ERR_IO_PENDING if | |
62 // the write will complete asynchronously, in which case |callback| will be | |
63 // called when it completes. Otherwise, returns a code other than | |
64 // ERR_IO_PENDING and does not invoke |callback|. Note that this method will | |
65 // not necessarily write data back to the cache if the incoming data is | |
66 // equivalent to the existing cached data. See the source of this function for | |
67 // details about how this function drives the state machine. | |
68 net::Error MaybeWriteHeaders(HttpResponseInfoIOBuffer* headers, | |
69 const OnWriteCompleteCallback& callback); | |
70 | |
71 // Writes the supplied body data |data| back to the cache. Returns | |
72 // ERR_IO_PENDING if the write will complete asynchronously, in which case | |
73 // |callback| will be called when it completes. Otherwise, returns a code | |
74 // other than ERR_IO_PENDING and does not invoke |callback|. Note that this | |
75 // method will not necessarily write data back to the cache if the incoming | |
76 // data is equivalent to the existing cached data. See the source of this | |
77 // function for details about how this function drives the state machine. | |
78 net::Error MaybeWriteData(net::IOBuffer* buf, | |
79 size_t buf_size, | |
80 const OnWriteCompleteCallback& callback); | |
81 | |
82 // Returns a count of bytes written back to the cache. | |
83 size_t bytes_written() const { return bytes_written_; } | |
84 bool did_replace() const { return did_replace_; } | |
85 | |
86 private: | |
87 // States for the state machine. | |
88 // | |
89 // The state machine flows roughly like this: if there is no existing cache | |
90 // entry, incoming headers and data are written directly back to the cache | |
91 // ("passthrough mode", the PASSTHROUGH states). If there is an existing cache | |
92 // entry, incoming headers and data are compared to the existing cache entry | |
93 // ("compare mode", the COMPARE states); if at any point the incoming | |
94 // headers/data are not equal to the cached headers/data, this class copies | |
95 // the cached data up to the point where the incoming data and the cached data | |
96 // diverged ("copy mode", the COPY states), then switches to "passthrough | |
97 // mode" to write the remainder of the incoming data. The overall effect is to | |
98 // avoid rewriting the cache entry if the incoming data is identical to the | |
99 // cached data. | |
100 // | |
101 // Note that after a call to MaybeWriteHeaders or MaybeWriteData completes, | |
102 // the machine is always in STATE_DONE, indicating that the call is finished; | |
103 // those methods are responsible for setting a new initial state. | |
104 enum State { | |
105 STATE_START, | |
106 // Control flows linearly through these four states, then loops from | |
107 // READ_DATA_FOR_COMPARE_DONE to READ_DATA_FOR_COMPARE, or exits to | |
108 // READ_HEADERS_FOR_COPY. | |
109 STATE_READ_HEADERS_FOR_COMPARE, | |
110 STATE_READ_HEADERS_FOR_COMPARE_DONE, | |
111 STATE_READ_DATA_FOR_COMPARE, | |
112 STATE_READ_DATA_FOR_COMPARE_DONE, | |
113 | |
114 // Control flows linearly through these states, with each pass from | |
115 // READ_DATA_FOR_COPY to WRITE_DATA_FOR_COPY_DONE copying one block of data | |
116 // at a time. Control loops from WRITE_DATA_FOR_COPY_DONE back to | |
117 // READ_DATA_FOR_COPY if there is more data to copy, or exits to | |
118 // WRITE_DATA_FOR_PASSTHROUGH. | |
119 STATE_READ_HEADERS_FOR_COPY, | |
120 STATE_READ_HEADERS_FOR_COPY_DONE, | |
121 STATE_WRITE_HEADERS_FOR_COPY, | |
122 STATE_WRITE_HEADERS_FOR_COPY_DONE, | |
123 STATE_READ_DATA_FOR_COPY, | |
124 STATE_READ_DATA_FOR_COPY_DONE, | |
125 STATE_WRITE_DATA_FOR_COPY, | |
126 STATE_WRITE_DATA_FOR_COPY_DONE, | |
127 | |
128 // Control flows linearly through these states, with a loop between | |
129 // WRITE_DATA_FOR_PASSTHROUGH and WRITE_DATA_FOR_PASSTHROUGH_DONE. | |
130 STATE_WRITE_HEADERS_FOR_PASSTHROUGH, | |
131 STATE_WRITE_HEADERS_FOR_PASSTHROUGH_DONE, | |
132 STATE_WRITE_DATA_FOR_PASSTHROUGH, | |
133 STATE_WRITE_DATA_FOR_PASSTHROUGH_DONE, | |
134 | |
135 // This state means "done with the current call; ready for another one." | |
136 STATE_DONE, | |
137 }; | |
138 | |
139 // Drives this class's state machine. This function steps the state machine | |
140 // until one of: | |
141 // a) One of the state functions returns an error | |
142 // b) The state machine reaches STATE_DONE | |
143 // A successful value (net::OK or greater) indicates that the requested | |
144 // operation completed synchronously. A return value of ERR_IO_PENDING | |
145 // indicates that some step had to submit asynchronous IO for later | |
146 // completion, and the state machine will resume running (via AsyncDoLoop) | |
147 // when that asynchronous IO completes. Any other return value indicates that | |
148 // the requested operation failed synchronously. | |
149 int DoLoop(int result); | |
150 | |
151 // State handlers. See function comments in the corresponding source file for | |
152 // details on these. | |
153 int DoStart(int result); | |
154 int DoReadHeadersForCompare(int result); | |
155 int DoReadHeadersForCompareDone(int result); | |
156 int DoReadDataForCompare(int result); | |
157 int DoReadDataForCompareDone(int result); | |
158 int DoReadHeadersForCopy(int result); | |
159 int DoReadHeadersForCopyDone(int result); | |
160 int DoWriteHeadersForCopy(int result); | |
161 int DoWriteHeadersForCopyDone(int result); | |
162 int DoReadDataForCopy(int result); | |
163 int DoReadDataForCopyDone(int result); | |
164 int DoWriteDataForCopy(int result); | |
165 int DoWriteDataForCopyDone(int result); | |
166 int DoWriteHeadersForPassthrough(int result); | |
167 int DoWriteHeadersForPassthroughDone(int result); | |
168 int DoWriteDataForPassthrough(int result); | |
169 int DoWriteDataForPassthroughDone(int result); | |
170 int DoDone(int result); | |
171 | |
172 // Wrappers for asynchronous calls. These are responsible for scheduling a | |
173 // callback to drive the state machine if needed. These either: | |
174 // a) Return ERR_IO_PENDING, and schedule a callback to run the state | |
175 // machine's Run() later, or | |
176 // b) Return some other value and do not schedule a callback. | |
177 int ReadInfoHelper(const scoped_ptr<ServiceWorkerResponseReader>& reader, | |
178 HttpResponseInfoIOBuffer* buf); | |
179 int ReadDataHelper(const scoped_ptr<ServiceWorkerResponseReader>& reader, | |
180 net::IOBuffer* buf, | |
181 int buf_len); | |
182 int WriteInfoHelper(const scoped_ptr<ServiceWorkerResponseWriter>& writer, | |
183 HttpResponseInfoIOBuffer* buf); | |
184 int WriteDataHelper(const scoped_ptr<ServiceWorkerResponseWriter>& writer, | |
185 net::IOBuffer* buf, | |
186 int buf_len); | |
187 | |
188 // Callback used by the above helpers for their IO operations. This is only | |
189 // run when those IO operations complete asynchronously, in which case it | |
190 // invokes the synchronous DoLoop function and runs the client callback (the | |
191 // one passed into MaybeWriteData/MaybeWriteHeaders) if that invocation | |
192 // of DoLoop completes synchronously. | |
193 void AsyncDoLoop(int result); | |
194 | |
195 State state_; | |
196 // Note that this variable is only used for assertions; it reflects "state != | |
197 // DONE && not in synchronous DoLoop". | |
198 bool io_pending_; | |
199 bool comparing_; | |
200 | |
201 scoped_refptr<HttpResponseInfoIOBuffer> headers_to_read_; | |
202 scoped_refptr<HttpResponseInfoIOBuffer> headers_to_write_; | |
203 scoped_refptr<net::IOBuffer> data_to_read_; | |
204 int len_to_read_; | |
205 scoped_refptr<net::IOBuffer> data_to_copy_; | |
206 scoped_refptr<net::IOBuffer> data_to_write_; | |
207 int len_to_write_; | |
208 OnWriteCompleteCallback pending_callback_; | |
209 | |
210 size_t cached_length_; | |
211 | |
212 size_t bytes_compared_; | |
213 size_t bytes_copied_; | |
214 size_t bytes_written_; | |
215 | |
216 bool did_replace_; | |
217 | |
218 size_t compare_offset_; | |
219 | |
220 ResponseReaderCreator reader_creator_; | |
221 ResponseWriterCreator writer_creator_; | |
222 scoped_ptr<ServiceWorkerResponseReader> compare_reader_; | |
223 scoped_ptr<ServiceWorkerResponseReader> copy_reader_; | |
224 scoped_ptr<ServiceWorkerResponseWriter> writer_; | |
225 base::WeakPtrFactory<ServiceWorkerCacheWriter> weak_factory_; | |
226 }; | |
227 | |
228 } // namespace content | |
229 | |
230 #endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CACHE_WRITER_H_ | |
OLD | NEW |