• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Chromium Authors
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 NET_HTTP_HTTP_CACHE_WRITERS_H_
6 #define NET_HTTP_HTTP_CACHE_WRITERS_H_
7 
8 #include <map>
9 #include <memory>
10 
11 #include "base/memory/raw_ptr.h"
12 #include "base/memory/weak_ptr.h"
13 #include "net/base/completion_once_callback.h"
14 #include "net/http/http_cache.h"
15 #include "net/http/http_response_info.h"
16 
17 namespace crypto {
18 class SecureHash;
19 }
20 
21 namespace net {
22 
23 class HttpResponseInfo;
24 class IOBuffer;
25 class PartialData;
26 
27 // If multiple HttpCache::Transactions are accessing the same cache entry
28 // simultaneously, their access to the data read from network is synchronized
29 // by HttpCache::Writers. This enables each of those transactions to drive
30 // reading the response body from the network ensuring a slow consumer does not
31 // starve other consumers of the same resource.
32 //
33 // Writers represents the set of all HttpCache::Transactions that are reading
34 // from the network using the same network transaction and writing to the same
35 // cache entry. It is owned by the ActiveEntry. The writers object must be
36 // deleted when HttpCache::WritersDoneWritingToEntry is called as it doesn't
37 // expect any of its ongoing IO transactions (e.g., network reads or cache
38 // writers) to complete after that point and won't know what to do with them.
39 class NET_EXPORT_PRIVATE HttpCache::Writers {
40  public:
41   // This is the information maintained by Writers in the context of each
42   // transaction.
43   // |partial| is owned by the transaction and to be sure there are no
44   // dangling pointers, it must be ensured that transaction's reference and
45   // this information will be removed from writers once the transaction is
46   // deleted.
47   struct NET_EXPORT_PRIVATE TransactionInfo {
48     TransactionInfo(PartialData* partial,
49                     bool truncated,
50                     HttpResponseInfo info);
51     ~TransactionInfo();
52     TransactionInfo& operator=(const TransactionInfo&);
53     TransactionInfo(const TransactionInfo&);
54 
55     raw_ptr<PartialData> partial;
56     bool truncated;
57     HttpResponseInfo response_info;
58   };
59 
60   // |cache| and |entry| must outlive this object.
61   Writers(HttpCache* cache, HttpCache::ActiveEntry* entry);
62 
63   Writers(const Writers&) = delete;
64   Writers& operator=(const Writers&) = delete;
65 
66   ~Writers();
67 
68   // Retrieves data from the network transaction associated with the Writers
69   // object. This may be done directly (via a network read into |*buf->data()|)
70   // or indirectly (by copying from another transactions buffer into
71   // |*buf->data()| on network read completion) depending on whether or not a
72   // read is currently in progress. May return the result synchronously or
73   // return ERR_IO_PENDING: if ERR_IO_PENDING is returned, |callback| will be
74   // run to inform the consumer of the result of the Read().
75   // |transaction| may be removed while Read() is ongoing. In that case Writers
76   // will still complete the Read() processing but will not invoke the
77   // |callback|.
78   int Read(scoped_refptr<IOBuffer> buf,
79            int buf_len,
80            CompletionOnceCallback callback,
81            Transaction* transaction);
82 
83   // Invoked when StopCaching is called on a member transaction.
84   // It stops caching only if there are no other transactions. Returns true if
85   // caching can be stopped.
86   // |keep_entry| should be true if the entry needs to be preserved after
87   // truncation.
88   bool StopCaching(bool keep_entry);
89 
90   // Membership functions like AddTransaction and RemoveTransaction are invoked
91   // by HttpCache on behalf of the HttpCache::Transaction.
92 
93   // Adds an HttpCache::Transaction to Writers.
94   // Should only be invoked if CanAddWriters() returns true.
95   // |parallel_writing_pattern| governs whether writing is an exclusive
96   // operation implying that Writers can contain at most one transaction till
97   // the completion of the response body. It is illegal to invoke with
98   // |parallel_writing_pattern| as PARALLEL_WRITING_NOT_JOIN*  if there is
99   // already a transaction present.
100   // |transaction| can be destroyed at any point and it should invoke
101   // HttpCache::DoneWithEntry() during its destruction. This will also ensure
102   // any pointers in |info| are not accessed after the transaction is destroyed.
103   void AddTransaction(Transaction* transaction,
104                       ParallelWritingPattern initial_writing_pattern,
105                       RequestPriority priority,
106                       const TransactionInfo& info);
107 
108   // Invoked when the transaction is done working with the entry.
109   void RemoveTransaction(Transaction* transaction, bool success);
110 
111   // Invoked when there is a change in a member transaction's priority or a
112   // member transaction is removed.
113   void UpdatePriority();
114 
115   // Returns true if this object is empty.
IsEmpty()116   bool IsEmpty() const { return all_writers_.empty(); }
117 
118   // Returns true if |transaction| is part of writers.
HasTransaction(const Transaction * transaction)119   bool HasTransaction(const Transaction* transaction) const {
120     return all_writers_.count(const_cast<Transaction*>(transaction)) > 0;
121   }
122 
123   // Returns true if more writers can be added for shared writing. Also fills in
124   // the |reason| for why a transaction cannot be added.
125   bool CanAddWriters(ParallelWritingPattern* reason);
126 
127   // Returns if only one transaction can be a member of writers.
IsExclusive()128   bool IsExclusive() const { return is_exclusive_; }
129 
130   // Returns the network transaction which may be nullptr for range requests.
network_transaction()131   const HttpTransaction* network_transaction() const {
132     return network_transaction_.get();
133   }
134 
135   void CloseConnectionOnDestruction();
136 
137   // Returns the load state of the |network_transaction_| if present else
138   // returns LOAD_STATE_IDLE.
139   LoadState GetLoadState() const;
140 
141   // Sets the network transaction argument to |network_transaction_|. Must be
142   // invoked before Read can be invoked. If |checksum| is set it will be
143   // validated and the cache entry will be marked unusable if it doesn't match.
144   void SetNetworkTransaction(
145       Transaction* transaction,
146       std::unique_ptr<HttpTransaction> network_transaction,
147       std::unique_ptr<crypto::SecureHash> checksum);
148 
149   // Resets the network transaction to nullptr. Required for range requests as
150   // they might use the current network transaction only for part of the
151   // request. Must only be invoked for range requests.
152   void ResetNetworkTransaction();
153 
154   // Returns if response is only being read from the network.
network_read_only()155   bool network_read_only() const { return network_read_only_; }
156 
GetTransactionsCount()157   int GetTransactionsCount() const { return all_writers_.size(); }
158 
159  private:
160   friend class WritersTest;
161 
162   enum class State {
163     UNSET,
164     NONE,
165     NETWORK_READ,
166     NETWORK_READ_COMPLETE,
167     CACHE_WRITE_DATA,
168     CACHE_WRITE_DATA_COMPLETE,
169     MARK_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE,
170     MARK_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE_COMPLETE,
171   };
172 
173   // These transactions are waiting on Read. After the active transaction
174   // completes writing the data to the cache, their buffer would be filled with
175   // the data and their callback will be invoked.
176   struct WaitingForRead {
177     scoped_refptr<IOBuffer> read_buf;
178     int read_buf_len;
179     int write_len = 0;
180     CompletionOnceCallback callback;
181     WaitingForRead(scoped_refptr<IOBuffer> read_buf,
182                    int len,
183                    CompletionOnceCallback consumer_callback);
184     ~WaitingForRead();
185     WaitingForRead(WaitingForRead&&);
186   };
187   using WaitingForReadMap = std::map<Transaction*, WaitingForRead>;
188 
189   using TransactionMap = std::map<Transaction*, TransactionInfo>;
190 
191   // Runs the state transition loop. Resets and calls |callback_| on exit,
192   // unless the return value is ERR_IO_PENDING.
193   int DoLoop(int result);
194 
195   // State machine functions.
196   int DoNetworkRead();
197   int DoNetworkReadComplete(int result);
198   int DoCacheWriteData(int num_bytes);
199   int DoCacheWriteDataComplete(int result);
200   int DoMarkSingleKeyedCacheEntryUnusable();
201   int DoMarkSingleKeyedCacheEntryUnusableComplete(int result);
202 
203   // Helper functions for callback.
204   void OnNetworkReadFailure(int result);
205   void OnCacheWriteFailure();
206   void OnDataReceived(int result);
207 
208   // Completes any pending IO_PENDING read operations by copying any received
209   // bytes from read_buf_ to the given buffer and posts a task to run the
210   // callback with |result|.
211   void CompleteWaitingForReadTransactions(int result);
212 
213   // Removes idle writers, passing |result| which is to be used for any
214   // subsequent read transaction.
215   void RemoveIdleWriters(int result);
216 
217   // Invoked when |active_transaction_| fails to read from network or write to
218   // cache. |error| indicates network read error code or cache write error.
219   void ProcessFailure(int error);
220 
221   // Returns true if |this| only contains idle writers. Idle writers are those
222   // that are waiting for Read to be invoked by the consumer.
223   bool ContainsOnlyIdleWriters() const;
224 
225   // Returns true if its worth marking the entry as truncated.
226   // TODO(shivanisha): Refactor this so that it could be const.
227   bool ShouldTruncate();
228 
229   // Enqueues a truncation operation to the entry. Ignores the response.
230   void TruncateEntry();
231 
232   // Remove the transaction.
233   void EraseTransaction(Transaction* transaction, int result);
234   TransactionMap::iterator EraseTransaction(TransactionMap::iterator it,
235                                             int result);
236   void SetCacheCallback(bool success, const TransactionSet& make_readers);
237 
238   // IO Completion callback function.
239   void OnIOComplete(int result);
240 
241   State next_state_ = State::NONE;
242 
243   // True if only reading from network and not writing to cache.
244   bool network_read_only_ = false;
245 
246   raw_ptr<HttpCache> const cache_ = nullptr;
247 
248   // Owner of |this|.
249   raw_ptr<ActiveEntry, DanglingUntriaged> const entry_ = nullptr;
250 
251   std::unique_ptr<HttpTransaction> network_transaction_;
252 
253   scoped_refptr<IOBuffer> read_buf_;
254 
255   int io_buf_len_ = 0;
256   int write_len_ = 0;
257 
258   // The cache transaction that is the current consumer of network_transaction_
259   // ::Read or writing to the entry and is waiting for the operation to be
260   // completed. This is used to ensure there is at most one consumer of
261   // network_transaction_ at a time.
262   raw_ptr<Transaction> active_transaction_ = nullptr;
263 
264   // Transactions whose consumers have invoked Read, but another transaction is
265   // currently the |active_transaction_|. After the network read and cache write
266   // is complete, the waiting transactions will be notified.
267   WaitingForReadMap waiting_for_read_;
268 
269   // Includes all transactions. ResetStateForEmptyWriters should be invoked
270   // whenever all_writers_ becomes empty.
271   TransactionMap all_writers_;
272 
273   // True if multiple transactions are not allowed e.g. for partial requests.
274   bool is_exclusive_ = false;
275   ParallelWritingPattern parallel_writing_pattern_ = PARALLEL_WRITING_NONE;
276 
277   // Current priority of the request. It is always the maximum of all the writer
278   // transactions.
279   RequestPriority priority_ = MINIMUM_PRIORITY;
280 
281   // Response info of the most recent transaction added to Writers will be used
282   // to write back the headers along with the truncated bit set. This is done so
283   // that we don't overwrite headers written by a more recent transaction with
284   // older headers while truncating.
285   HttpResponseInfo response_info_truncation_;
286 
287   // Do not mark a partial request as truncated if it is not already a truncated
288   // entry to start with.
289   bool partial_do_not_truncate_ = false;
290 
291   // True if the entry should be kept, even if the response was not completely
292   // written.
293   bool should_keep_entry_ = true;
294 
295   // The latest time `this` starts writing data to the disk cache.
296   base::TimeTicks last_disk_cache_access_start_time_;
297 
298   // Set if we are currently calculating a checksum of the resource to validate
299   // it against the expected checksum for the single-keyed cache. Initialised
300   // with selected headers and accumulates the body of the response.
301   std::unique_ptr<crypto::SecureHash> checksum_;
302 
303   CompletionOnceCallback callback_;  // Callback for active_transaction_.
304 
305   // Since cache_ can destroy |this|, |cache_callback_| is only invoked at the
306   // end of DoLoop().
307   base::OnceClosure cache_callback_;  // Callback for cache_.
308 
309   base::WeakPtrFactory<Writers> weak_factory_{this};
310 };
311 
312 }  // namespace net
313 
314 #endif  // NET_HTTP_HTTP_CACHE_WRITERS_H_
315