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