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