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 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
158 new_response_(NULL), | 158 new_response_(NULL), |
159 mode_(NONE), | 159 mode_(NONE), |
160 reading_(false), | 160 reading_(false), |
161 invalid_range_(false), | 161 invalid_range_(false), |
162 truncated_(false), | 162 truncated_(false), |
163 is_sparse_(false), | 163 is_sparse_(false), |
164 range_requested_(false), | 164 range_requested_(false), |
165 handling_206_(false), | 165 handling_206_(false), |
166 cache_pending_(false), | 166 cache_pending_(false), |
167 done_reading_(false), | 167 done_reading_(false), |
| 168 done_headers_create_new_entry_(false), |
168 vary_mismatch_(false), | 169 vary_mismatch_(false), |
169 couldnt_conditionalize_request_(false), | 170 couldnt_conditionalize_request_(false), |
170 bypass_lock_for_test_(false), | 171 bypass_lock_for_test_(false), |
171 bypass_lock_after_headers_for_test_(false), | 172 bypass_lock_after_headers_for_test_(false), |
172 fail_conditionalization_for_test_(false), | 173 fail_conditionalization_for_test_(false), |
173 io_buf_len_(0), | 174 io_buf_len_(0), |
174 read_offset_(0), | 175 read_offset_(0), |
175 effective_load_flags_(0), | 176 effective_load_flags_(0), |
176 write_len_(0), | 177 write_len_(0), |
177 cache_entry_status_(CacheEntryStatus::ENTRY_UNDEFINED), | 178 cache_entry_status_(CacheEntryStatus::ENTRY_UNDEFINED), |
(...skipping 575 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
753 case STATE_CREATE_ENTRY_COMPLETE: | 754 case STATE_CREATE_ENTRY_COMPLETE: |
754 rv = DoCreateEntryComplete(rv); | 755 rv = DoCreateEntryComplete(rv); |
755 break; | 756 break; |
756 case STATE_ADD_TO_ENTRY: | 757 case STATE_ADD_TO_ENTRY: |
757 DCHECK_EQ(OK, rv); | 758 DCHECK_EQ(OK, rv); |
758 rv = DoAddToEntry(); | 759 rv = DoAddToEntry(); |
759 break; | 760 break; |
760 case STATE_ADD_TO_ENTRY_COMPLETE: | 761 case STATE_ADD_TO_ENTRY_COMPLETE: |
761 rv = DoAddToEntryComplete(rv); | 762 rv = DoAddToEntryComplete(rv); |
762 break; | 763 break; |
| 764 case STATE_DONE_HEADERS_ADD_TO_ENTRY_COMPLETE: |
| 765 rv = DoDoneHeadersAddToEntryComplete(rv); |
| 766 break; |
763 case STATE_CACHE_READ_RESPONSE: | 767 case STATE_CACHE_READ_RESPONSE: |
764 DCHECK_EQ(OK, rv); | 768 DCHECK_EQ(OK, rv); |
765 rv = DoCacheReadResponse(); | 769 rv = DoCacheReadResponse(); |
766 break; | 770 break; |
767 case STATE_CACHE_READ_RESPONSE_COMPLETE: | 771 case STATE_CACHE_READ_RESPONSE_COMPLETE: |
768 rv = DoCacheReadResponseComplete(rv); | 772 rv = DoCacheReadResponseComplete(rv); |
769 break; | 773 break; |
770 case STATE_TOGGLE_UNUSED_SINCE_PREFETCH: | 774 case STATE_TOGGLE_UNUSED_SINCE_PREFETCH: |
771 DCHECK_EQ(OK, rv); | 775 DCHECK_EQ(OK, rv); |
772 rv = DoCacheToggleUnusedSincePrefetch(); | 776 rv = DoCacheToggleUnusedSincePrefetch(); |
(...skipping 339 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1112 case ERR_CACHE_RACE: | 1116 case ERR_CACHE_RACE: |
1113 TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED); | 1117 TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED); |
1114 break; | 1118 break; |
1115 | 1119 |
1116 default: | 1120 default: |
1117 // We have a race here: Maybe we failed to open the entry and decided to | 1121 // We have a race here: Maybe we failed to open the entry and decided to |
1118 // create one, but by the time we called create, another transaction | 1122 // create one, but by the time we called create, another transaction |
1119 // already created the entry. If we want to eliminate this issue, we | 1123 // already created the entry. If we want to eliminate this issue, we |
1120 // need an atomic OpenOrCreate() method exposed by the disk cache. | 1124 // need an atomic OpenOrCreate() method exposed by the disk cache. |
1121 DLOG(WARNING) << "Unable to create cache entry"; | 1125 DLOG(WARNING) << "Unable to create cache entry"; |
| 1126 |
| 1127 // Set the mode to NONE in order to bypass the cache entry and read from |
| 1128 // the network directly. |
1122 mode_ = NONE; | 1129 mode_ = NONE; |
1123 if (partial_) | 1130 if (!done_headers_create_new_entry_) { |
1124 partial_->RestoreHeaders(&custom_request_->extra_headers); | 1131 if (partial_) |
1125 TransitionToState(STATE_SEND_REQUEST); | 1132 partial_->RestoreHeaders(&custom_request_->extra_headers); |
| 1133 TransitionToState(STATE_SEND_REQUEST); |
| 1134 return OK; |
| 1135 } |
| 1136 // The headers have already been received as a result of validation, |
| 1137 // triggering the doom of the old entry. So no network request needs to |
| 1138 // be sent. Note that since mode_ is NONE, the response won't be written |
| 1139 // to cache. Transition to STATE_CACHE_WRITE_RESPONSE as that's the state |
| 1140 // the transaction left off on when it tried to create the new entry. |
| 1141 done_headers_create_new_entry_ = false; |
| 1142 TransitionToState(STATE_CACHE_WRITE_RESPONSE); |
1126 } | 1143 } |
1127 return OK; | 1144 return OK; |
1128 } | 1145 } |
1129 | 1146 |
1130 int HttpCache::Transaction::DoAddToEntry() { | 1147 int HttpCache::Transaction::DoAddToEntry() { |
1131 TRACE_EVENT0("io", "HttpCacheTransaction::DoAddToEntry"); | 1148 TRACE_EVENT0("io", "HttpCacheTransaction::DoAddToEntry"); |
1132 DCHECK(new_entry_); | 1149 DCHECK(new_entry_); |
1133 cache_pending_ = true; | 1150 cache_pending_ = true; |
1134 TransitionToState(STATE_ADD_TO_ENTRY_COMPLETE); | |
1135 net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_ADD_TO_ENTRY); | 1151 net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_ADD_TO_ENTRY); |
1136 DCHECK(entry_lock_waiting_since_.is_null()); | 1152 DCHECK(entry_lock_waiting_since_.is_null()); |
| 1153 int rv = cache_->AddTransactionToEntry(new_entry_, this); |
| 1154 DCHECK_EQ(rv, ERR_IO_PENDING); |
| 1155 |
| 1156 // If headers phase is already done then we are here because of validation not |
| 1157 // matching and creating a new entry. This transaction should be the |
| 1158 // first transaction of that new entry and thus it should not be subject |
| 1159 // to any cache lock delays, thus returning early from here. |
| 1160 if (done_headers_create_new_entry_) { |
| 1161 DCHECK_EQ(mode_, WRITE); |
| 1162 TransitionToState(STATE_DONE_HEADERS_ADD_TO_ENTRY_COMPLETE); |
| 1163 return rv; |
| 1164 } |
| 1165 |
| 1166 TransitionToState(STATE_ADD_TO_ENTRY_COMPLETE); |
| 1167 |
1137 entry_lock_waiting_since_ = TimeTicks::Now(); | 1168 entry_lock_waiting_since_ = TimeTicks::Now(); |
1138 int rv = cache_->AddTransactionToEntry(new_entry_, this); | 1169 AddCacheLockTimeoutHandler(new_entry_); |
1139 if (rv == ERR_IO_PENDING) | |
1140 AddCacheLockTimeoutHandler(new_entry_); | |
1141 return rv; | 1170 return rv; |
1142 } | 1171 } |
1143 | 1172 |
1144 void HttpCache::Transaction::AddCacheLockTimeoutHandler(ActiveEntry* entry) { | 1173 void HttpCache::Transaction::AddCacheLockTimeoutHandler(ActiveEntry* entry) { |
1145 DCHECK(next_state_ == STATE_ADD_TO_ENTRY_COMPLETE || | 1174 DCHECK(next_state_ == STATE_ADD_TO_ENTRY_COMPLETE || |
1146 next_state_ == STATE_FINISH_HEADERS_COMPLETE); | 1175 next_state_ == STATE_FINISH_HEADERS_COMPLETE); |
1147 if ((bypass_lock_for_test_ && next_state_ == STATE_ADD_TO_ENTRY_COMPLETE) || | 1176 if ((bypass_lock_for_test_ && next_state_ == STATE_ADD_TO_ENTRY_COMPLETE) || |
1148 (bypass_lock_after_headers_for_test_ && | 1177 (bypass_lock_after_headers_for_test_ && |
1149 next_state_ == STATE_FINISH_HEADERS_COMPLETE)) { | 1178 next_state_ == STATE_FINISH_HEADERS_COMPLETE)) { |
1150 base::ThreadTaskRunnerHandle::Get()->PostTask( | 1179 base::ThreadTaskRunnerHandle::Get()->PostTask( |
1151 FROM_HERE, | 1180 FROM_HERE, |
1152 base::Bind(&HttpCache::Transaction::OnCacheLockTimeout, | 1181 base::Bind(&HttpCache::Transaction::OnCacheLockTimeout, |
1153 weak_factory_.GetWeakPtr(), entry_lock_waiting_since_)); | 1182 weak_factory_.GetWeakPtr(), entry_lock_waiting_since_)); |
1154 } else { | 1183 } else { |
1155 int timeout_milliseconds = 20 * 1000; | 1184 int timeout_milliseconds = 20 * 1000; |
1156 if (partial_ && entry->writer && entry->writer->range_requested_) { | 1185 if (partial_ && entry->writer && entry->writer->range_requested_) { |
1157 // Quickly timeout and bypass the cache if we're a range request and | |
1158 // we're blocked by the reader/writer lock. Doing so eliminates a long | 1186 // we're blocked by the reader/writer lock. Doing so eliminates a long |
1159 // running issue, http://crbug.com/31014, where two of the same media | 1187 // running issue, http://crbug.com/31014, where two of the same media |
1160 // resources could not be played back simultaneously due to one locking | 1188 // resources could not be played back simultaneously due to one locking |
1161 // the cache entry until the entire video was downloaded. | 1189 // the cache entry until the entire video was downloaded. |
1162 // | 1190 // |
1163 // Bypassing the cache is not ideal, as we are now ignoring the cache | 1191 // Bypassing the cache is not ideal, as we are now ignoring the cache |
1164 // entirely for all range requests to a resource beyond the first. This | 1192 // entirely for all range requests to a resource beyond the first. This |
1165 // is however a much more succinct solution than the alternatives, which | 1193 // is however a much more succinct solution than the alternatives, which |
1166 // would require somewhat significant changes to the http caching logic. | 1194 // would require somewhat significant changes to the http caching logic. |
1167 // | 1195 // |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1235 partial_->RestoreHeaders(&custom_request_->extra_headers); | 1263 partial_->RestoreHeaders(&custom_request_->extra_headers); |
1236 TransitionToState(STATE_SEND_REQUEST); | 1264 TransitionToState(STATE_SEND_REQUEST); |
1237 } else { | 1265 } else { |
1238 // We have to read the headers from the cached entry. | 1266 // We have to read the headers from the cached entry. |
1239 DCHECK(mode_ & READ_META); | 1267 DCHECK(mode_ & READ_META); |
1240 TransitionToState(STATE_CACHE_READ_RESPONSE); | 1268 TransitionToState(STATE_CACHE_READ_RESPONSE); |
1241 } | 1269 } |
1242 return OK; | 1270 return OK; |
1243 } | 1271 } |
1244 | 1272 |
| 1273 int HttpCache::Transaction::DoDoneHeadersAddToEntryComplete(int result) { |
| 1274 // This transaction's response headers did not match its ActiveEntry so it |
| 1275 // created a new ActiveEntry (new_entry_) to write to (and doomed the old |
| 1276 // one). Now that the new entry has been created, start writing the response. |
| 1277 |
| 1278 DCHECK_EQ(result, OK); |
| 1279 DCHECK_EQ(mode_, WRITE); |
| 1280 DCHECK(new_entry_); |
| 1281 DCHECK(response_.headers); |
| 1282 |
| 1283 cache_pending_ = false; |
| 1284 entry_ = new_entry_; |
| 1285 done_headers_create_new_entry_ = false; |
| 1286 DCHECK_NE(response_.headers->response_code(), 304); |
| 1287 DCHECK(cache_->CanTransactionWriteResponseHeaders( |
| 1288 entry_, this, partial_ != nullptr, false)); |
| 1289 TransitionToState(STATE_CACHE_WRITE_RESPONSE); |
| 1290 return OK; |
| 1291 } |
| 1292 |
1245 int HttpCache::Transaction::DoCacheReadResponse() { | 1293 int HttpCache::Transaction::DoCacheReadResponse() { |
1246 TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheReadResponse"); | 1294 TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheReadResponse"); |
1247 DCHECK(entry_); | 1295 DCHECK(entry_); |
1248 TransitionToState(STATE_CACHE_READ_RESPONSE_COMPLETE); | 1296 TransitionToState(STATE_CACHE_READ_RESPONSE_COMPLETE); |
1249 | 1297 |
1250 io_buf_len_ = entry_->disk_entry->GetDataSize(kResponseInfoIndex); | 1298 io_buf_len_ = entry_->disk_entry->GetDataSize(kResponseInfoIndex); |
1251 read_buf_ = new IOBuffer(io_buf_len_); | 1299 read_buf_ = new IOBuffer(io_buf_len_); |
1252 | 1300 |
1253 net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_READ_INFO); | 1301 net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_READ_INFO); |
1254 return entry_->disk_entry->ReadData(kResponseInfoIndex, 0, read_buf_.get(), | 1302 return entry_->disk_entry->ReadData(kResponseInfoIndex, 0, read_buf_.get(), |
(...skipping 465 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1720 TransitionToState(STATE_PARTIAL_HEADERS_RECEIVED); | 1768 TransitionToState(STATE_PARTIAL_HEADERS_RECEIVED); |
1721 return OK; | 1769 return OK; |
1722 } | 1770 } |
1723 | 1771 |
1724 TransitionToState(STATE_CACHE_WRITE_RESPONSE); | 1772 TransitionToState(STATE_CACHE_WRITE_RESPONSE); |
1725 return OK; | 1773 return OK; |
1726 } | 1774 } |
1727 | 1775 |
1728 int HttpCache::Transaction::DoCacheWriteResponse() { | 1776 int HttpCache::Transaction::DoCacheWriteResponse() { |
1729 TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheWriteResponse"); | 1777 TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheWriteResponse"); |
1730 TransitionToState(STATE_CACHE_WRITE_RESPONSE_COMPLETE); | |
1731 | 1778 |
1732 // Invalidate any current entry with a successful response if this transaction | 1779 // Invalidate any current entry with a successful response if this transaction |
1733 // cannot write to this entry. This transaction then continues to read from | 1780 // cannot write to this entry. This transaction then continues to read from |
1734 // the network without writing to the backend. | 1781 // the network without writing to the backend. |
1735 bool is_match = response_.headers->response_code() == 304; | 1782 bool is_match = response_.headers->response_code() == 304; |
1736 if (entry_ && response_.headers && | 1783 if (entry_ && response_.headers && |
1737 !cache_->CanTransactionWriteResponseHeaders( | 1784 !cache_->CanTransactionWriteResponseHeaders( |
1738 entry_, this, partial_ != nullptr, is_match)) { | 1785 entry_, this, partial_ != nullptr, is_match)) { |
1739 cache_->DoneWritingToEntry(entry_, false, this); | 1786 done_headers_create_new_entry_ = true; |
| 1787 |
| 1788 // The transaction needs to overwrite this response. Doom the current entry, |
| 1789 // create a new one (by going to STATE_INIT_ENTRY), and then jump straight |
| 1790 // to writing out the response, bypassing the headers checks. The mode_ is |
| 1791 // set to WRITE in order to doom any other existing entries that might exist |
| 1792 // so that this transaction can go straight to writing a response. |
| 1793 mode_ = WRITE; |
| 1794 TransitionToState(STATE_INIT_ENTRY); |
| 1795 cache_->DoomEntryValidationNoMatch(entry_); |
1740 entry_ = nullptr; | 1796 entry_ = nullptr; |
1741 mode_ = NONE; | |
1742 return OK; | 1797 return OK; |
1743 } | 1798 } |
1744 | 1799 |
| 1800 TransitionToState(STATE_CACHE_WRITE_RESPONSE_COMPLETE); |
1745 return WriteResponseInfoToEntry(truncated_); | 1801 return WriteResponseInfoToEntry(truncated_); |
1746 } | 1802 } |
1747 | 1803 |
1748 int HttpCache::Transaction::DoCacheWriteResponseComplete(int result) { | 1804 int HttpCache::Transaction::DoCacheWriteResponseComplete(int result) { |
1749 TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheWriteResponseComplete"); | 1805 TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheWriteResponseComplete"); |
1750 TransitionToState(STATE_TRUNCATE_CACHED_DATA); | 1806 TransitionToState(STATE_TRUNCATE_CACHED_DATA); |
1751 return OnWriteResponseInfoToEntryComplete(result); | 1807 return OnWriteResponseInfoToEntryComplete(result); |
1752 } | 1808 } |
1753 | 1809 |
1754 int HttpCache::Transaction::DoTruncateCachedData() { | 1810 int HttpCache::Transaction::DoTruncateCachedData() { |
(...skipping 1408 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3163 } | 3219 } |
3164 | 3220 |
3165 void HttpCache::Transaction::TransitionToState(State state) { | 3221 void HttpCache::Transaction::TransitionToState(State state) { |
3166 // Ensure that the state is only set once per Do* state. | 3222 // Ensure that the state is only set once per Do* state. |
3167 DCHECK(in_do_loop_); | 3223 DCHECK(in_do_loop_); |
3168 DCHECK_EQ(STATE_UNSET, next_state_) << "Next state is " << state; | 3224 DCHECK_EQ(STATE_UNSET, next_state_) << "Next state is " << state; |
3169 next_state_ = state; | 3225 next_state_ = state; |
3170 } | 3226 } |
3171 | 3227 |
3172 } // namespace net | 3228 } // namespace net |
OLD | NEW |