Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(425)

Side by Side Diff: net/http/http_cache_transaction.cc

Issue 2774603003: Doom and create new entry when validation is not a match (Closed)
Patch Set: Feedback addressed. Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698