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 vary_mismatch_(false), | |
168 couldnt_conditionalize_request_(false), | 167 couldnt_conditionalize_request_(false), |
169 bypass_lock_for_test_(false), | 168 bypass_lock_for_test_(false), |
170 fail_conditionalization_for_test_(false), | 169 fail_conditionalization_for_test_(false), |
171 io_buf_len_(0), | 170 io_buf_len_(0), |
172 read_offset_(0), | 171 read_offset_(0), |
173 effective_load_flags_(0), | 172 effective_load_flags_(0), |
174 write_len_(0), | 173 write_len_(0), |
175 cache_entry_status_(CacheEntryStatus::ENTRY_UNDEFINED), | 174 cache_entry_status_(CacheEntryStatus::ENTRY_UNDEFINED), |
176 validation_cause_(VALIDATION_CAUSE_UNDEFINED), | 175 validation_cause_(VALIDATION_CAUSE_UNDEFINED), |
177 total_received_bytes_(0), | 176 total_received_bytes_(0), |
(...skipping 1912 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2090 TransitionToState(STATE_NONE); | 2089 TransitionToState(STATE_NONE); |
2091 return ERR_CACHE_MISS; | 2090 return ERR_CACHE_MISS; |
2092 } | 2091 } |
2093 | 2092 |
2094 // We don't have the whole resource. | 2093 // We don't have the whole resource. |
2095 if (truncated_) { | 2094 if (truncated_) { |
2096 TransitionToState(STATE_NONE); | 2095 TransitionToState(STATE_NONE); |
2097 return ERR_CACHE_MISS; | 2096 return ERR_CACHE_MISS; |
2098 } | 2097 } |
2099 | 2098 |
2100 if (RequiresValidation()) { | 2099 if (GetEntryValidationStatus() != USABLE) { |
2101 TransitionToState(STATE_NONE); | 2100 TransitionToState(STATE_NONE); |
2102 return ERR_CACHE_MISS; | 2101 return ERR_CACHE_MISS; |
2103 } | 2102 } |
2104 | 2103 |
2105 if (request_->method == "HEAD") | 2104 if (request_->method == "HEAD") |
2106 FixHeadersForHead(); | 2105 FixHeadersForHead(); |
2107 | 2106 |
2108 if (entry_->disk_entry->GetDataSize(kMetadataIndex)) | 2107 if (entry_->disk_entry->GetDataSize(kMetadataIndex)) |
2109 TransitionToState(STATE_CACHE_READ_METADATA); | 2108 TransitionToState(STATE_CACHE_READ_METADATA); |
2110 else | 2109 else |
2111 TransitionToState(STATE_NONE); | 2110 TransitionToState(STATE_NONE); |
2112 | 2111 |
2113 return OK; | 2112 return OK; |
2114 } | 2113 } |
2115 | 2114 |
2116 int HttpCache::Transaction::BeginCacheValidation() { | 2115 int HttpCache::Transaction::BeginCacheValidation() { |
2117 DCHECK_EQ(mode_, READ_WRITE); | 2116 DCHECK_EQ(mode_, READ_WRITE); |
2118 | 2117 |
2119 bool skip_validation = !RequiresValidation(); | 2118 enum EntryValidationStatus entry_validation_status = |
2119 GetEntryValidationStatus(); | |
2120 | 2120 |
2121 if (request_->method == "HEAD" && | 2121 if (request_->method == "HEAD" && |
2122 (truncated_ || response_.headers->response_code() == 206)) { | 2122 (truncated_ || response_.headers->response_code() == 206)) { |
2123 DCHECK(!partial_); | 2123 DCHECK(!partial_); |
2124 if (skip_validation) | 2124 if (entry_validation_status == USABLE) |
2125 return SetupEntryForRead(); | 2125 return SetupEntryForRead(); |
2126 | 2126 |
2127 // Bail out! | 2127 // Bail out! |
2128 TransitionToState(STATE_SEND_REQUEST); | 2128 TransitionToState(STATE_SEND_REQUEST); |
2129 mode_ = NONE; | 2129 mode_ = NONE; |
2130 return OK; | 2130 return OK; |
2131 } | 2131 } |
2132 | 2132 |
2133 if (truncated_) { | 2133 if (truncated_) { |
2134 // Truncated entries can cause partial gets, so we shouldn't record this | 2134 // Truncated entries can cause partial gets, so we shouldn't record this |
2135 // load in histograms. | 2135 // load in histograms. |
2136 UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_OTHER); | 2136 UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_OTHER); |
2137 skip_validation = !partial_->initial_validation(); | |
2138 } | 2137 } |
2139 | 2138 |
2140 if (partial_ && (is_sparse_ || truncated_) && | 2139 if (entry_validation_status == USABLE) { |
2141 (!partial_->IsCurrentRangeCached() || invalid_range_)) { | 2140 UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_USED); |
2142 // Force revalidation for sparse or truncated entries. Note that we don't | 2141 return SetupEntryForRead(); |
2143 // want to ignore the regular validation logic just because a byte range was | |
2144 // part of the request. | |
2145 skip_validation = false; | |
2146 } | 2142 } |
2147 | 2143 |
2148 if (skip_validation) { | 2144 // If the network request cannot be conditional, setup a normal |
2149 UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_USED); | 2145 // fetch. The mode remains READ_WRITE for a conditional request. |
2150 return SetupEntryForRead(); | 2146 // Even if the conditionalization fails, don't switch to WRITE mode |
2151 } else { | 2147 // until it is confirmed that the transaction won't be falling back |
2152 // Make the network request conditional, to see if we may reuse our cached | 2148 // to using the cache entry in the LOAD_FROM_CACHE_IF_OFFLINE case. |
2153 // response. If we cannot do so, then we just resort to a normal fetch. | 2149 if (entry_validation_status == REQUIRES_REFETCH) { |
2154 // Our mode remains READ_WRITE for a conditional request. Even if the | 2150 couldnt_conditionalize_request_ = true; |
shivanisha
2017/05/02 16:03:25
Can we save entry_validation_status as a member va
| |
2155 // conditionalization fails, we don't switch to WRITE mode until we | 2151 UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_CANT_CONDITIONALIZE); |
2156 // know we won't be falling back to using the cache entry in the | 2152 if (partial_) |
2157 // LOAD_FROM_CACHE_IF_OFFLINE case. | 2153 return DoRestartPartialRequest(); |
2158 if (!ConditionalizeRequest()) { | |
2159 couldnt_conditionalize_request_ = true; | |
2160 UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_CANT_CONDITIONALIZE); | |
2161 if (partial_) | |
2162 return DoRestartPartialRequest(); | |
2163 | 2154 |
2164 DCHECK_NE(206, response_.headers->response_code()); | 2155 DCHECK_NE(206, response_.headers->response_code()); |
2156 TransitionToState(STATE_SEND_REQUEST); | |
2157 return OK; | |
2158 } | |
2159 | |
2160 // Sending a conditional request to see if the cache entry is still valid. | |
2161 | |
2162 // Setup custom request if needed. | |
2163 if (!partial_) { | |
2164 custom_request_.reset(new HttpRequestInfo(*request_)); | |
2165 request_ = custom_request_.get(); | |
2166 } | |
2167 DCHECK(custom_request_.get()); | |
2168 bool use_if_range = | |
2169 partial_ && !partial_->IsCurrentRangeCached() && !invalid_range_; | |
2170 | |
2171 std::string etag_value; | |
2172 if (response_.headers->GetHttpVersion() >= HttpVersion(1, 1)) | |
2173 response_.headers->EnumerateHeader(NULL, "etag", &etag_value); | |
2174 | |
2175 std::string last_modified_value; | |
2176 if (entry_validation_status == REQUIRES_VALIDATION_VARY_MISMATCH) { | |
2177 response_.headers->EnumerateHeader(NULL, "last-modified", | |
2178 &last_modified_value); | |
shivanisha
2017/05/02 16:03:26
The above two conditions seem to be getting execut
| |
2179 } | |
2180 | |
shivanisha
2017/05/02 16:03:25
DCHECK(!etag_value.empty() || !last_modified_value
| |
2181 if (!etag_value.empty()) { | |
2182 if (use_if_range) { | |
2183 // We don't want to switch to WRITE mode if we don't have this block of a | |
2184 // byte-range request because we may have other parts cached. | |
2185 custom_request_->extra_headers.SetHeader(HttpRequestHeaders::kIfRange, | |
2186 etag_value); | |
2187 } else { | |
2188 custom_request_->extra_headers.SetHeader(HttpRequestHeaders::kIfNoneMatch, | |
2189 etag_value); | |
2165 } | 2190 } |
2166 TransitionToState(STATE_SEND_REQUEST); | |
2167 } | 2191 } |
2192 | |
2193 if (!last_modified_value.empty() && | |
2194 // For byte-range requests, make sure that we use only one way to validate | |
2195 // the request. | |
2196 (!partial_ || partial_->IsCurrentRangeCached())) { | |
2197 if (use_if_range) { | |
2198 custom_request_->extra_headers.SetHeader(HttpRequestHeaders::kIfRange, | |
2199 last_modified_value); | |
2200 } else { | |
2201 custom_request_->extra_headers.SetHeader( | |
2202 HttpRequestHeaders::kIfModifiedSince, last_modified_value); | |
2203 } | |
2204 } | |
2205 | |
2206 TransitionToState(STATE_SEND_REQUEST); | |
2168 return OK; | 2207 return OK; |
2169 } | 2208 } |
2170 | 2209 |
2171 int HttpCache::Transaction::BeginPartialCacheValidation() { | 2210 int HttpCache::Transaction::BeginPartialCacheValidation() { |
2172 DCHECK_EQ(mode_, READ_WRITE); | 2211 DCHECK_EQ(mode_, READ_WRITE); |
2173 | 2212 |
2174 if (response_.headers->response_code() != 206 && !partial_ && !truncated_) | 2213 if (response_.headers->response_code() != 206 && !partial_ && !truncated_) |
2175 return BeginCacheValidation(); | 2214 return BeginCacheValidation(); |
2176 | 2215 |
2177 // Partial requests should not be recorded in histograms. | 2216 // Partial requests should not be recorded in histograms. |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2275 DCHECK(network_trans_.get()); | 2314 DCHECK(network_trans_.get()); |
2276 DCHECK_EQ(STATE_NONE, next_state_); | 2315 DCHECK_EQ(STATE_NONE, next_state_); |
2277 | 2316 |
2278 next_state_ = STATE_SEND_REQUEST_COMPLETE; | 2317 next_state_ = STATE_SEND_REQUEST_COMPLETE; |
2279 int rv = network_trans_->RestartWithAuth(credentials, io_callback_); | 2318 int rv = network_trans_->RestartWithAuth(credentials, io_callback_); |
2280 if (rv != ERR_IO_PENDING) | 2319 if (rv != ERR_IO_PENDING) |
2281 return DoLoop(rv); | 2320 return DoLoop(rv); |
2282 return rv; | 2321 return rv; |
2283 } | 2322 } |
2284 | 2323 |
2285 bool HttpCache::Transaction::RequiresValidation() { | 2324 // Helper function for GetEntryValidationStatus. |
2325 bool HttpCache::Transaction::RequiresValidation(bool* vary_mismatch) const { | |
2326 if (partial_ && (is_sparse_ || truncated_) && | |
2327 (!partial_->IsCurrentRangeCached() || invalid_range_)) { | |
2328 // Force revalidation for sparse or truncated entries. Note that | |
2329 // we don't want to ignore the regular validation logic just | |
2330 // because a byte range was part of the request. | |
2331 return true; | |
2332 } | |
2333 | |
2334 // In the truncation case, validation status is controlled by the | |
2335 // partial_ state; that state either determines that it's usable, or | |
2336 // forces validation. | |
2337 if (truncated_ && request_->method != "HEAD") | |
2338 return partial_->initial_validation(); | |
2339 | |
2286 // TODO(darin): need to do more work here: | 2340 // TODO(darin): need to do more work here: |
2287 // - make sure we have a matching request method | 2341 // - make sure we have a matching request method |
2288 // - watch out for cached responses that depend on authentication | 2342 // - watch out for cached responses that depend on authentication |
2289 | |
2290 if (!(effective_load_flags_ & LOAD_SKIP_VARY_CHECK) && | 2343 if (!(effective_load_flags_ & LOAD_SKIP_VARY_CHECK) && |
2291 response_.vary_data.is_valid() && | 2344 response_.vary_data.is_valid() && |
2292 !response_.vary_data.MatchesRequest(*request_, | 2345 !response_.vary_data.MatchesRequest(*request_, |
2293 *response_.headers.get())) { | 2346 *response_.headers.get())) { |
2294 vary_mismatch_ = true; | 2347 *vary_mismatch = true; |
2295 validation_cause_ = VALIDATION_CAUSE_VARY_MISMATCH; | 2348 validation_cause_ = VALIDATION_CAUSE_VARY_MISMATCH; |
2296 return true; | 2349 return true; |
2297 } | 2350 } |
2298 | 2351 |
2299 if (effective_load_flags_ & LOAD_SKIP_CACHE_VALIDATION) | 2352 if (effective_load_flags_ & LOAD_SKIP_CACHE_VALIDATION) |
2300 return false; | 2353 return false; |
2301 | 2354 |
2302 if (response_.unused_since_prefetch && | 2355 if (response_.unused_since_prefetch && |
2303 !(effective_load_flags_ & LOAD_PREFETCH) && | 2356 !(effective_load_flags_ & LOAD_PREFETCH) && |
2304 response_.headers->GetCurrentAge( | 2357 (response_.headers->GetCurrentAge(response_.request_time, |
2305 response_.request_time, response_.response_time, | 2358 response_.response_time, |
2306 cache_->clock_->Now()) < TimeDelta::FromMinutes(kPrefetchReuseMins)) { | 2359 cache_->clock_->Now()) < |
2360 TimeDelta::FromMinutes(kPrefetchReuseMins))) { | |
2307 // The first use of a resource after prefetch within a short window skips | 2361 // The first use of a resource after prefetch within a short window skips |
2308 // validation. | 2362 // validation. |
2309 return false; | 2363 return false; |
2310 } | 2364 } |
2311 | 2365 |
2312 if (effective_load_flags_ & LOAD_VALIDATE_CACHE) { | 2366 if (effective_load_flags_ & LOAD_VALIDATE_CACHE) { |
2313 validation_cause_ = VALIDATION_CAUSE_VALIDATE_FLAG; | 2367 validation_cause_ = VALIDATION_CAUSE_VALIDATE_FLAG; |
2314 return true; | 2368 return true; |
2315 } | 2369 } |
2316 | 2370 |
2317 if (request_->method == "PUT" || request_->method == "DELETE") | |
2318 return true; | |
2319 | |
2320 bool validation_required_by_headers = response_.headers->RequiresValidation( | 2371 bool validation_required_by_headers = response_.headers->RequiresValidation( |
2321 response_.request_time, response_.response_time, cache_->clock_->Now()); | 2372 response_.request_time, response_.response_time, cache_->clock_->Now()); |
2322 | 2373 |
2323 if (validation_required_by_headers) { | 2374 if (validation_required_by_headers) { |
2324 HttpResponseHeaders::FreshnessLifetimes lifetimes = | 2375 HttpResponseHeaders::FreshnessLifetimes lifetimes = |
2325 response_.headers->GetFreshnessLifetimes(response_.response_time); | 2376 response_.headers->GetFreshnessLifetimes(response_.response_time); |
2326 if (lifetimes.freshness == base::TimeDelta()) { | 2377 if (lifetimes.freshness == base::TimeDelta()) { |
2327 validation_cause_ = VALIDATION_CAUSE_ZERO_FRESHNESS; | 2378 validation_cause_ = VALIDATION_CAUSE_ZERO_FRESHNESS; |
2328 } else { | 2379 } else { |
2329 validation_cause_ = VALIDATION_CAUSE_STALE; | 2380 validation_cause_ = VALIDATION_CAUSE_STALE; |
2330 stale_entry_freshness_ = lifetimes.freshness; | 2381 stale_entry_freshness_ = lifetimes.freshness; |
2331 stale_entry_age_ = response_.headers->GetCurrentAge( | 2382 stale_entry_age_ = response_.headers->GetCurrentAge( |
2332 response_.request_time, response_.response_time, | 2383 response_.request_time, response_.response_time, |
2333 cache_->clock_->Now()); | 2384 cache_->clock_->Now()); |
2334 } | 2385 } |
2335 } | 2386 } |
2336 | 2387 |
2337 return validation_required_by_headers; | 2388 return validation_required_by_headers; |
2338 } | 2389 } |
2339 | 2390 |
2340 bool HttpCache::Transaction::ConditionalizeRequest() { | 2391 HttpCache::Transaction::EntryValidationStatus |
2341 DCHECK(response_.headers.get()); | 2392 HttpCache::Transaction::GetEntryValidationStatus() const { |
2393 if (request_->method == "PUT" || request_->method == "DELETE") | |
2394 return REQUIRES_REFETCH; | |
shivanisha
2017/05/02 16:03:26
In the original code, this check comes after the o
| |
2342 | 2395 |
2343 if (request_->method == "PUT" || request_->method == "DELETE") | 2396 bool vary_mismatch = false; |
2344 return false; | 2397 if (!RequiresValidation(&vary_mismatch)) |
2398 return USABLE; | |
2345 | 2399 |
2346 // This only makes sense for cached 200 or 206 responses. | 2400 // The transaction requires revalidation with the server, and may require |
2401 // a re-fetch. | |
2347 if (response_.headers->response_code() != 200 && | 2402 if (response_.headers->response_code() != 200 && |
2348 response_.headers->response_code() != 206) { | 2403 response_.headers->response_code() != 206) { |
2349 return false; | 2404 return REQUIRES_REFETCH; |
2350 } | 2405 } |
2351 | 2406 |
2352 if (fail_conditionalization_for_test_) | 2407 if (fail_conditionalization_for_test_) |
2353 return false; | 2408 return REQUIRES_REFETCH; |
2354 | 2409 |
2355 DCHECK(response_.headers->response_code() != 206 || | 2410 DCHECK(response_.headers->response_code() != 206 || |
2356 response_.headers->HasStrongValidators()); | 2411 response_.headers->HasStrongValidators()); |
2357 | 2412 |
2358 // Just use the first available ETag and/or Last-Modified header value. | 2413 // Just use the first available ETag and/or Last-Modified header value. |
2359 // TODO(darin): Or should we use the last? | 2414 // TODO(darin): Or should we use the last? |
2360 | 2415 |
2361 std::string etag_value; | 2416 std::string etag_value; |
2362 if (response_.headers->GetHttpVersion() >= HttpVersion(1, 1)) | 2417 if (response_.headers->GetHttpVersion() >= HttpVersion(1, 1)) |
2363 response_.headers->EnumerateHeader(NULL, "etag", &etag_value); | 2418 response_.headers->EnumerateHeader(NULL, "etag", &etag_value); |
2364 | 2419 |
2365 std::string last_modified_value; | 2420 std::string last_modified_value; |
2366 if (!vary_mismatch_) { | 2421 if (!vary_mismatch) { |
2367 response_.headers->EnumerateHeader(NULL, "last-modified", | 2422 response_.headers->EnumerateHeader(NULL, "last-modified", |
2368 &last_modified_value); | 2423 &last_modified_value); |
2369 } | 2424 } |
2370 | 2425 |
2371 if (etag_value.empty() && last_modified_value.empty()) | 2426 if (etag_value.empty() && last_modified_value.empty()) |
2372 return false; | 2427 return REQUIRES_REFETCH; |
2373 | 2428 |
2374 if (!partial_) { | 2429 return vary_mismatch ? REQUIRES_VALIDATION |
2375 // Need to customize the request, so this forces us to allocate :( | 2430 : REQUIRES_VALIDATION_VARY_MISMATCH; |
shivanisha
2017/05/02 16:03:25
Looks like it should be REQUIRES_VALIDATION_VARY_M
| |
2376 custom_request_.reset(new HttpRequestInfo(*request_)); | |
2377 request_ = custom_request_.get(); | |
2378 } | |
2379 DCHECK(custom_request_.get()); | |
2380 | |
2381 bool use_if_range = | |
2382 partial_ && !partial_->IsCurrentRangeCached() && !invalid_range_; | |
2383 | |
2384 if (!etag_value.empty()) { | |
2385 if (use_if_range) { | |
2386 // We don't want to switch to WRITE mode if we don't have this block of a | |
2387 // byte-range request because we may have other parts cached. | |
2388 custom_request_->extra_headers.SetHeader( | |
2389 HttpRequestHeaders::kIfRange, etag_value); | |
2390 } else { | |
2391 custom_request_->extra_headers.SetHeader( | |
2392 HttpRequestHeaders::kIfNoneMatch, etag_value); | |
2393 } | |
2394 // For byte-range requests, make sure that we use only one way to validate | |
2395 // the request. | |
2396 if (partial_ && !partial_->IsCurrentRangeCached()) | |
2397 return true; | |
2398 } | |
2399 | |
2400 if (!last_modified_value.empty()) { | |
2401 if (use_if_range) { | |
2402 custom_request_->extra_headers.SetHeader( | |
2403 HttpRequestHeaders::kIfRange, last_modified_value); | |
2404 } else { | |
2405 custom_request_->extra_headers.SetHeader( | |
2406 HttpRequestHeaders::kIfModifiedSince, last_modified_value); | |
2407 } | |
2408 } | |
2409 | |
2410 return true; | |
2411 } | 2431 } |
2412 | 2432 |
2413 // We just received some headers from the server. We may have asked for a range, | 2433 // We just received some headers from the server. We may have asked for a range, |
2414 // in which case partial_ has an object. This could be the first network request | 2434 // in which case partial_ has an object. This could be the first network request |
2415 // we make to fulfill the original request, or we may be already reading (from | 2435 // we make to fulfill the original request, or we may be already reading (from |
2416 // the net and / or the cache). If we are not expecting a certain response, we | 2436 // the net and / or the cache). If we are not expecting a certain response, we |
2417 // just bypass the cache for this request (but again, maybe we are reading), and | 2437 // just bypass the cache for this request (but again, maybe we are reading), and |
2418 // delete partial_ (so we are not able to "fix" the headers that we return to | 2438 // delete partial_ (so we are not able to "fix" the headers that we return to |
2419 // the user). This results in either a weird response for the caller (we don't | 2439 // the user). This results in either a weird response for the caller (we don't |
2420 // expect it after all), or maybe a range that was not exactly what it was asked | 2440 // expect it after all), or maybe a range that was not exactly what it was asked |
(...skipping 596 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3017 } | 3037 } |
3018 | 3038 |
3019 void HttpCache::Transaction::TransitionToState(State state) { | 3039 void HttpCache::Transaction::TransitionToState(State state) { |
3020 // Ensure that the state is only set once per Do* state. | 3040 // Ensure that the state is only set once per Do* state. |
3021 DCHECK(in_do_loop_); | 3041 DCHECK(in_do_loop_); |
3022 DCHECK_EQ(STATE_UNSET, next_state_) << "Next state is " << state; | 3042 DCHECK_EQ(STATE_UNSET, next_state_) << "Next state is " << state; |
3023 next_state_ = state; | 3043 next_state_ = state; |
3024 } | 3044 } |
3025 | 3045 |
3026 } // namespace net | 3046 } // namespace net |
OLD | NEW |