Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/http/http_cache_transaction.h" | 5 #include "net/http/http_cache_transaction.h" |
| 6 | 6 |
| 7 #include "build/build_config.h" // For OS_POSIX | 7 #include "build/build_config.h" // For OS_POSIX |
| 8 | 8 |
| 9 #if defined(OS_POSIX) | 9 #if defined(OS_POSIX) |
| 10 #include <unistd.h> | 10 #include <unistd.h> |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 157 new_response_(NULL), | 157 new_response_(NULL), |
| 158 mode_(NONE), | 158 mode_(NONE), |
| 159 reading_(false), | 159 reading_(false), |
| 160 invalid_range_(false), | 160 invalid_range_(false), |
| 161 truncated_(false), | 161 truncated_(false), |
| 162 is_sparse_(false), | 162 is_sparse_(false), |
| 163 range_requested_(false), | 163 range_requested_(false), |
| 164 handling_206_(false), | 164 handling_206_(false), |
| 165 cache_pending_(false), | 165 cache_pending_(false), |
| 166 done_reading_(false), | 166 done_reading_(false), |
| 167 done_headers_create_new_entry_(false), | |
| 167 vary_mismatch_(false), | 168 vary_mismatch_(false), |
| 168 couldnt_conditionalize_request_(false), | 169 couldnt_conditionalize_request_(false), |
| 169 bypass_lock_for_test_(false), | 170 bypass_lock_for_test_(false), |
| 170 fail_conditionalization_for_test_(false), | 171 fail_conditionalization_for_test_(false), |
| 171 io_buf_len_(0), | 172 io_buf_len_(0), |
| 172 read_offset_(0), | 173 read_offset_(0), |
| 173 effective_load_flags_(0), | 174 effective_load_flags_(0), |
| 174 write_len_(0), | 175 write_len_(0), |
| 175 cache_entry_status_(CacheEntryStatus::ENTRY_UNDEFINED), | 176 cache_entry_status_(CacheEntryStatus::ENTRY_UNDEFINED), |
| 176 validation_cause_(VALIDATION_CAUSE_UNDEFINED), | 177 validation_cause_(VALIDATION_CAUSE_UNDEFINED), |
| (...skipping 573 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 750 case STATE_CREATE_ENTRY_COMPLETE: | 751 case STATE_CREATE_ENTRY_COMPLETE: |
| 751 rv = DoCreateEntryComplete(rv); | 752 rv = DoCreateEntryComplete(rv); |
| 752 break; | 753 break; |
| 753 case STATE_ADD_TO_ENTRY: | 754 case STATE_ADD_TO_ENTRY: |
| 754 DCHECK_EQ(OK, rv); | 755 DCHECK_EQ(OK, rv); |
| 755 rv = DoAddToEntry(); | 756 rv = DoAddToEntry(); |
| 756 break; | 757 break; |
| 757 case STATE_ADD_TO_ENTRY_COMPLETE: | 758 case STATE_ADD_TO_ENTRY_COMPLETE: |
| 758 rv = DoAddToEntryComplete(rv); | 759 rv = DoAddToEntryComplete(rv); |
| 759 break; | 760 break; |
| 761 case STATE_DONE_HEADERS_ADD_TO_ENTRY_COMPLETE: | |
| 762 rv = DoDoneHeadersAddToEntryComplete(rv); | |
| 763 break; | |
| 760 case STATE_CACHE_READ_RESPONSE: | 764 case STATE_CACHE_READ_RESPONSE: |
| 761 DCHECK_EQ(OK, rv); | 765 DCHECK_EQ(OK, rv); |
| 762 rv = DoCacheReadResponse(); | 766 rv = DoCacheReadResponse(); |
| 763 break; | 767 break; |
| 764 case STATE_CACHE_READ_RESPONSE_COMPLETE: | 768 case STATE_CACHE_READ_RESPONSE_COMPLETE: |
| 765 rv = DoCacheReadResponseComplete(rv); | 769 rv = DoCacheReadResponseComplete(rv); |
| 766 break; | 770 break; |
| 767 case STATE_TOGGLE_UNUSED_SINCE_PREFETCH: | 771 case STATE_TOGGLE_UNUSED_SINCE_PREFETCH: |
| 768 DCHECK_EQ(OK, rv); | 772 DCHECK_EQ(OK, rv); |
| 769 rv = DoCacheToggleUnusedSincePrefetch(); | 773 rv = DoCacheToggleUnusedSincePrefetch(); |
| (...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1108 case ERR_CACHE_RACE: | 1112 case ERR_CACHE_RACE: |
| 1109 TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED); | 1113 TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED); |
| 1110 break; | 1114 break; |
| 1111 | 1115 |
| 1112 default: | 1116 default: |
| 1113 // We have a race here: Maybe we failed to open the entry and decided to | 1117 // We have a race here: Maybe we failed to open the entry and decided to |
| 1114 // create one, but by the time we called create, another transaction | 1118 // create one, but by the time we called create, another transaction |
| 1115 // already created the entry. If we want to eliminate this issue, we | 1119 // already created the entry. If we want to eliminate this issue, we |
| 1116 // need an atomic OpenOrCreate() method exposed by the disk cache. | 1120 // need an atomic OpenOrCreate() method exposed by the disk cache. |
| 1117 DLOG(WARNING) << "Unable to create cache entry"; | 1121 DLOG(WARNING) << "Unable to create cache entry"; |
| 1122 // Switching into passing through data directly from the network, avoiding | |
|
jkarlin
2017/06/16 18:28:01
Suggest: Set the mode to NONE in order to bypass t
shivanisha
2017/06/27 15:31:14
done
| |
| 1123 // the cache entry. | |
| 1118 mode_ = NONE; | 1124 mode_ = NONE; |
| 1119 if (partial_) | 1125 if (!done_headers_create_new_entry_) { |
| 1120 partial_->RestoreHeaders(&custom_request_->extra_headers); | 1126 if (partial_) |
| 1121 TransitionToState(STATE_SEND_REQUEST); | 1127 partial_->RestoreHeaders(&custom_request_->extra_headers); |
| 1128 TransitionToState(STATE_SEND_REQUEST); | |
| 1129 return OK; | |
| 1130 } | |
| 1131 // The headers have already been received as a result of validation, | |
| 1132 // triggering the doom of the old entry. So no network request needs to | |
| 1133 // be sent. Note that since mode_ is set to pass-through, response will | |
|
jkarlin
2017/06/16 18:28:01
Suggest: Note that since mode_ is NONE, the respon
shivanisha
2017/06/27 15:31:14
done
| |
| 1134 // not be written to the cache but moving to state | |
| 1135 // STATE_CACHE_WRITE_RESPONSE for consistency. | |
| 1136 done_headers_create_new_entry_ = false; | |
| 1137 TransitionToState(STATE_CACHE_WRITE_RESPONSE); | |
| 1122 } | 1138 } |
| 1123 return OK; | 1139 return OK; |
| 1124 } | 1140 } |
| 1125 | 1141 |
| 1126 int HttpCache::Transaction::DoAddToEntry() { | 1142 int HttpCache::Transaction::DoAddToEntry() { |
| 1127 TRACE_EVENT0("io", "HttpCacheTransaction::DoAddToEntry"); | 1143 TRACE_EVENT0("io", "HttpCacheTransaction::DoAddToEntry"); |
| 1128 DCHECK(new_entry_); | 1144 DCHECK(new_entry_); |
| 1129 cache_pending_ = true; | 1145 cache_pending_ = true; |
| 1130 TransitionToState(STATE_ADD_TO_ENTRY_COMPLETE); | |
| 1131 net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_ADD_TO_ENTRY); | 1146 net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_ADD_TO_ENTRY); |
| 1132 DCHECK(entry_lock_waiting_since_.is_null()); | 1147 DCHECK(entry_lock_waiting_since_.is_null()); |
| 1148 int rv = cache_->AddTransactionToEntry(new_entry_, this); | |
| 1149 DCHECK_EQ(rv, ERR_IO_PENDING); | |
| 1150 | |
| 1151 // If headers phase is already done and we are here because of validation not | |
| 1152 // matching and creating a new entry, then this transaction should be the | |
| 1153 // first transaction of that entry and thus it should not be subject | |
| 1154 // to any cache lock delays, thus returning early from here. | |
|
jkarlin
2017/06/16 18:28:01
This is a very long sentence, please break it up.
shivanisha
2017/06/27 15:31:14
done
| |
| 1155 if (done_headers_create_new_entry_) { | |
| 1156 DCHECK_EQ(mode_, WRITE); | |
| 1157 TransitionToState(STATE_DONE_HEADERS_ADD_TO_ENTRY_COMPLETE); | |
| 1158 return rv; | |
| 1159 } | |
| 1160 | |
| 1161 TransitionToState(STATE_ADD_TO_ENTRY_COMPLETE); | |
| 1133 entry_lock_waiting_since_ = TimeTicks::Now(); | 1162 entry_lock_waiting_since_ = TimeTicks::Now(); |
| 1134 int rv = cache_->AddTransactionToEntry(new_entry_, this); | 1163 |
| 1135 if (rv == ERR_IO_PENDING) { | 1164 if (bypass_lock_for_test_) { |
| 1136 if (bypass_lock_for_test_) { | 1165 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 1137 base::ThreadTaskRunnerHandle::Get()->PostTask( | 1166 FROM_HERE, |
| 1138 FROM_HERE, | 1167 base::Bind(&HttpCache::Transaction::OnAddToEntryTimeout, |
| 1139 base::Bind(&HttpCache::Transaction::OnAddToEntryTimeout, | 1168 weak_factory_.GetWeakPtr(), entry_lock_waiting_since_)); |
| 1140 weak_factory_.GetWeakPtr(), entry_lock_waiting_since_)); | 1169 } else { |
| 1141 } else { | 1170 int timeout_milliseconds = 20 * 1000; |
| 1142 int timeout_milliseconds = 20 * 1000; | 1171 if (partial_ && new_entry_->writer && |
| 1143 if (partial_ && new_entry_->writer && | 1172 new_entry_->writer->range_requested_) { |
| 1144 new_entry_->writer->range_requested_) { | 1173 // Quickly timeout and bypass the cache if we're a range request and |
| 1145 // Quickly timeout and bypass the cache if we're a range request and | 1174 // we're blocked by the reader/writer lock. Doing so eliminates a long |
| 1146 // we're blocked by the reader/writer lock. Doing so eliminates a long | 1175 // running issue, http://crbug.com/31014, where two of the same media |
| 1147 // running issue, http://crbug.com/31014, where two of the same media | 1176 // resources could not be played back simultaneously due to one locking |
| 1148 // resources could not be played back simultaneously due to one locking | 1177 // the cache entry until the entire video was downloaded. |
| 1149 // the cache entry until the entire video was downloaded. | 1178 // |
| 1150 // | 1179 // Bypassing the cache is not ideal, as we are now ignoring the cache |
| 1151 // Bypassing the cache is not ideal, as we are now ignoring the cache | 1180 // entirely for all range requests to a resource beyond the first. This |
| 1152 // entirely for all range requests to a resource beyond the first. This | 1181 // is however a much more succinct solution than the alternatives, which |
| 1153 // is however a much more succinct solution than the alternatives, which | 1182 // would require somewhat significant changes to the http caching logic. |
| 1154 // would require somewhat significant changes to the http caching logic. | 1183 // |
| 1155 // | 1184 // Allow some timeout slack for the entry addition to complete in case |
| 1156 // Allow some timeout slack for the entry addition to complete in case | 1185 // the writer lock is imminently released; we want to avoid skipping |
| 1157 // the writer lock is imminently released; we want to avoid skipping | 1186 // the cache if at all possible. See http://crbug.com/408765 |
| 1158 // the cache if at all possible. See http://crbug.com/408765 | 1187 timeout_milliseconds = 25; |
| 1159 timeout_milliseconds = 25; | |
| 1160 } | |
| 1161 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | |
| 1162 FROM_HERE, | |
| 1163 base::Bind(&HttpCache::Transaction::OnAddToEntryTimeout, | |
| 1164 weak_factory_.GetWeakPtr(), entry_lock_waiting_since_), | |
| 1165 TimeDelta::FromMilliseconds(timeout_milliseconds)); | |
| 1166 } | 1188 } |
| 1189 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | |
| 1190 FROM_HERE, | |
| 1191 base::Bind(&HttpCache::Transaction::OnAddToEntryTimeout, | |
| 1192 weak_factory_.GetWeakPtr(), entry_lock_waiting_since_), | |
| 1193 TimeDelta::FromMilliseconds(timeout_milliseconds)); | |
| 1167 } | 1194 } |
| 1195 | |
| 1168 return rv; | 1196 return rv; |
| 1169 } | 1197 } |
| 1170 | 1198 |
| 1171 int HttpCache::Transaction::DoAddToEntryComplete(int result) { | 1199 int HttpCache::Transaction::DoAddToEntryComplete(int result) { |
| 1172 TRACE_EVENT0("io", "HttpCacheTransaction::DoAddToEntryComplete"); | 1200 TRACE_EVENT0("io", "HttpCacheTransaction::DoAddToEntryComplete"); |
| 1173 net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_ADD_TO_ENTRY, | 1201 net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_ADD_TO_ENTRY, |
| 1174 result); | 1202 result); |
| 1175 const TimeDelta entry_lock_wait = | 1203 const TimeDelta entry_lock_wait = |
| 1176 TimeTicks::Now() - entry_lock_waiting_since_; | 1204 TimeTicks::Now() - entry_lock_waiting_since_; |
| 1177 UMA_HISTOGRAM_TIMES("HttpCache.EntryLockWait", entry_lock_wait); | 1205 UMA_HISTOGRAM_TIMES("HttpCache.EntryLockWait", entry_lock_wait); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1225 partial_->RestoreHeaders(&custom_request_->extra_headers); | 1253 partial_->RestoreHeaders(&custom_request_->extra_headers); |
| 1226 TransitionToState(STATE_SEND_REQUEST); | 1254 TransitionToState(STATE_SEND_REQUEST); |
| 1227 } else { | 1255 } else { |
| 1228 // We have to read the headers from the cached entry. | 1256 // We have to read the headers from the cached entry. |
| 1229 DCHECK(mode_ & READ_META); | 1257 DCHECK(mode_ & READ_META); |
| 1230 TransitionToState(STATE_CACHE_READ_RESPONSE); | 1258 TransitionToState(STATE_CACHE_READ_RESPONSE); |
| 1231 } | 1259 } |
| 1232 return OK; | 1260 return OK; |
| 1233 } | 1261 } |
| 1234 | 1262 |
| 1263 int HttpCache::Transaction::DoDoneHeadersAddToEntryComplete(int result) { | |
| 1264 // This state is reached when |this| has already completed validation leading | |
| 1265 // to a no-match with original entry which was doomed and |new_entry_| was | |
|
jkarlin
2017/06/16 18:28:01
Suggest: This transaction's response headers did n
shivanisha
2017/06/27 15:31:14
done
| |
| 1266 // created. A response of no-match from a validation request also includes the | |
| 1267 // full contents of the URL, so go ahead and write the response to the newly | |
| 1268 // created entry. | |
| 1269 | |
| 1270 DCHECK_EQ(result, OK); | |
| 1271 DCHECK_EQ(mode_, WRITE); | |
| 1272 DCHECK(new_entry_); | |
| 1273 DCHECK(response_.headers); | |
| 1274 | |
| 1275 cache_pending_ = false; | |
| 1276 entry_ = new_entry_; | |
| 1277 done_headers_create_new_entry_ = false; | |
| 1278 bool is_match = response_.headers->response_code() == 304; | |
|
jkarlin
2017/06/16 18:28:01
Hmm, can it be a 304? If it were a 304 then the tr
shivanisha
2017/06/27 15:31:14
done
| |
| 1279 DCHECK(cache_->CanTransactionWriteResponseHeaders( | |
| 1280 entry_, this, partial_ != nullptr, is_match)); | |
| 1281 TransitionToState(STATE_CACHE_WRITE_RESPONSE); | |
| 1282 return OK; | |
| 1283 } | |
| 1284 | |
| 1235 int HttpCache::Transaction::DoCacheReadResponse() { | 1285 int HttpCache::Transaction::DoCacheReadResponse() { |
| 1236 TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheReadResponse"); | 1286 TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheReadResponse"); |
| 1237 DCHECK(entry_); | 1287 DCHECK(entry_); |
| 1238 TransitionToState(STATE_CACHE_READ_RESPONSE_COMPLETE); | 1288 TransitionToState(STATE_CACHE_READ_RESPONSE_COMPLETE); |
| 1239 | 1289 |
| 1240 io_buf_len_ = entry_->disk_entry->GetDataSize(kResponseInfoIndex); | 1290 io_buf_len_ = entry_->disk_entry->GetDataSize(kResponseInfoIndex); |
| 1241 read_buf_ = new IOBuffer(io_buf_len_); | 1291 read_buf_ = new IOBuffer(io_buf_len_); |
| 1242 | 1292 |
| 1243 net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_READ_INFO); | 1293 net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_READ_INFO); |
| 1244 return entry_->disk_entry->ReadData(kResponseInfoIndex, 0, read_buf_.get(), | 1294 return entry_->disk_entry->ReadData(kResponseInfoIndex, 0, read_buf_.get(), |
| (...skipping 465 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1710 TransitionToState(STATE_PARTIAL_HEADERS_RECEIVED); | 1760 TransitionToState(STATE_PARTIAL_HEADERS_RECEIVED); |
| 1711 return OK; | 1761 return OK; |
| 1712 } | 1762 } |
| 1713 | 1763 |
| 1714 TransitionToState(STATE_CACHE_WRITE_RESPONSE); | 1764 TransitionToState(STATE_CACHE_WRITE_RESPONSE); |
| 1715 return OK; | 1765 return OK; |
| 1716 } | 1766 } |
| 1717 | 1767 |
| 1718 int HttpCache::Transaction::DoCacheWriteResponse() { | 1768 int HttpCache::Transaction::DoCacheWriteResponse() { |
| 1719 TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheWriteResponse"); | 1769 TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheWriteResponse"); |
| 1720 TransitionToState(STATE_CACHE_WRITE_RESPONSE_COMPLETE); | |
| 1721 | 1770 |
| 1722 // Invalidate any current entry with a successful response if this transaction | 1771 // Invalidate any current entry with a successful response if this transaction |
| 1723 // cannot write to this entry. This transaction then continues to read from | 1772 // cannot write to this entry. This transaction then continues to read from |
| 1724 // the network without writing to the backend. | 1773 // the network without writing to the backend. |
| 1725 bool is_match = response_.headers->response_code() == 304; | 1774 bool is_match = response_.headers->response_code() == 304; |
| 1726 if (entry_ && response_.headers && | 1775 if (entry_ && response_.headers && |
| 1727 !cache_->CanTransactionWriteResponseHeaders( | 1776 !cache_->CanTransactionWriteResponseHeaders( |
| 1728 entry_, this, partial_ != nullptr, is_match)) { | 1777 entry_, this, partial_ != nullptr, is_match)) { |
| 1729 cache_->DoneWritingToEntry(entry_, false, this); | 1778 done_headers_create_new_entry_ = true; |
| 1779 | |
| 1780 // This transaction should not add itself to any other existing entry but | |
| 1781 // create a new entry. Going to state STATE_INIT_ENTRY and setting mode_ to | |
| 1782 // WRITE will take care of dooming if any other entry exists. | |
|
jkarlin
2017/06/16 18:28:01
Suggest:
The transaction needs to overwrite this
shivanisha
2017/06/27 15:31:14
done
| |
| 1783 mode_ = WRITE; | |
| 1784 TransitionToState(STATE_INIT_ENTRY); | |
| 1785 cache_->DoomEntryValidationNoMatch(entry_, this); | |
| 1730 entry_ = nullptr; | 1786 entry_ = nullptr; |
| 1731 mode_ = NONE; | |
| 1732 return OK; | 1787 return OK; |
| 1733 } | 1788 } |
| 1734 | 1789 |
| 1790 TransitionToState(STATE_CACHE_WRITE_RESPONSE_COMPLETE); | |
| 1735 return WriteResponseInfoToEntry(truncated_); | 1791 return WriteResponseInfoToEntry(truncated_); |
| 1736 } | 1792 } |
| 1737 | 1793 |
| 1738 int HttpCache::Transaction::DoCacheWriteResponseComplete(int result) { | 1794 int HttpCache::Transaction::DoCacheWriteResponseComplete(int result) { |
| 1739 TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheWriteResponseComplete"); | 1795 TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheWriteResponseComplete"); |
| 1740 TransitionToState(STATE_TRUNCATE_CACHED_DATA); | 1796 TransitionToState(STATE_TRUNCATE_CACHED_DATA); |
| 1741 return OnWriteResponseInfoToEntryComplete(result); | 1797 return OnWriteResponseInfoToEntryComplete(result); |
| 1742 } | 1798 } |
| 1743 | 1799 |
| 1744 int HttpCache::Transaction::DoTruncateCachedData() { | 1800 int HttpCache::Transaction::DoTruncateCachedData() { |
| (...skipping 1379 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3124 } | 3180 } |
| 3125 | 3181 |
| 3126 void HttpCache::Transaction::TransitionToState(State state) { | 3182 void HttpCache::Transaction::TransitionToState(State state) { |
| 3127 // Ensure that the state is only set once per Do* state. | 3183 // Ensure that the state is only set once per Do* state. |
| 3128 DCHECK(in_do_loop_); | 3184 DCHECK(in_do_loop_); |
| 3129 DCHECK_EQ(STATE_UNSET, next_state_) << "Next state is " << state; | 3185 DCHECK_EQ(STATE_UNSET, next_state_) << "Next state is " << state; |
| 3130 next_state_ = state; | 3186 next_state_ = state; |
| 3131 } | 3187 } |
| 3132 | 3188 |
| 3133 } // namespace net | 3189 } // namespace net |
| OLD | NEW |