 Chromium Code Reviews
 Chromium Code Reviews Issue 391763002:
  Initial implementation of Chrome-Freshness header.  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@master
    
  
    Issue 391763002:
  Initial implementation of Chrome-Freshness header.  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@master| 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" | 7 #include "build/build_config.h" | 
| 8 | 8 | 
| 9 #if defined(OS_POSIX) | 9 #if defined(OS_POSIX) | 
| 10 #include <unistd.h> | 10 #include <unistd.h> | 
| 11 #endif | 11 #endif | 
| 12 | 12 | 
| 13 #include <algorithm> | 13 #include <algorithm> | 
| 14 #include <string> | 14 #include <string> | 
| 15 | 15 | 
| 16 #include "base/bind.h" | 16 #include "base/bind.h" | 
| 17 #include "base/compiler_specific.h" | 17 #include "base/compiler_specific.h" | 
| 18 #include "base/format_macros.h" | |
| 18 #include "base/memory/ref_counted.h" | 19 #include "base/memory/ref_counted.h" | 
| 19 #include "base/metrics/field_trial.h" | 20 #include "base/metrics/field_trial.h" | 
| 20 #include "base/metrics/histogram.h" | 21 #include "base/metrics/histogram.h" | 
| 21 #include "base/metrics/sparse_histogram.h" | 22 #include "base/metrics/sparse_histogram.h" | 
| 22 #include "base/rand_util.h" | 23 #include "base/rand_util.h" | 
| 23 #include "base/strings/string_number_conversions.h" | 24 #include "base/strings/string_number_conversions.h" | 
| 25 #include "base/strings/string_piece.h" | |
| 24 #include "base/strings/string_util.h" | 26 #include "base/strings/string_util.h" | 
| 27 #include "base/strings/stringprintf.h" | |
| 25 #include "base/time/time.h" | 28 #include "base/time/time.h" | 
| 26 #include "net/base/completion_callback.h" | 29 #include "net/base/completion_callback.h" | 
| 27 #include "net/base/io_buffer.h" | 30 #include "net/base/io_buffer.h" | 
| 28 #include "net/base/load_flags.h" | 31 #include "net/base/load_flags.h" | 
| 29 #include "net/base/load_timing_info.h" | 32 #include "net/base/load_timing_info.h" | 
| 30 #include "net/base/net_errors.h" | 33 #include "net/base/net_errors.h" | 
| 31 #include "net/base/net_log.h" | 34 #include "net/base/net_log.h" | 
| 32 #include "net/base/upload_data_stream.h" | 35 #include "net/base/upload_data_stream.h" | 
| 33 #include "net/cert/cert_status_flags.h" | 36 #include "net/cert/cert_status_flags.h" | 
| 34 #include "net/disk_cache/disk_cache.h" | 37 #include "net/disk_cache/disk_cache.h" | 
| 35 #include "net/http/disk_based_cert_cache.h" | 38 #include "net/http/disk_based_cert_cache.h" | 
| 36 #include "net/http/http_network_session.h" | 39 #include "net/http/http_network_session.h" | 
| 37 #include "net/http/http_request_info.h" | 40 #include "net/http/http_request_info.h" | 
| 38 #include "net/http/http_response_headers.h" | 41 #include "net/http/http_response_headers.h" | 
| 39 #include "net/http/http_transaction.h" | 42 #include "net/http/http_transaction.h" | 
| 40 #include "net/http/http_util.h" | 43 #include "net/http/http_util.h" | 
| 41 #include "net/http/partial_data.h" | 44 #include "net/http/partial_data.h" | 
| 42 #include "net/ssl/ssl_cert_request_info.h" | 45 #include "net/ssl/ssl_cert_request_info.h" | 
| 43 #include "net/ssl/ssl_config_service.h" | 46 #include "net/ssl/ssl_config_service.h" | 
| 44 | 47 | 
| 45 using base::Time; | 48 using base::Time; | 
| 46 using base::TimeDelta; | 49 using base::TimeDelta; | 
| 47 using base::TimeTicks; | 50 using base::TimeTicks; | 
| 48 | 51 | 
| 49 namespace { | 52 namespace { | 
| 50 | 53 | 
| 54 // TODO(ricea): Move this to HttpResponseHeaders once it is standardised. | |
| 55 static const char kFreshnessHeader[] = "Chrome-Freshness"; | |
| 
rvargas (doing something else)
2014/07/24 00:54:06
Shouldn't we use some other prefix that states mor
 
Adam Rice
2014/07/28 11:11:13
Okay, I've changed to "Chromium-Resource-Freshness
 | |
| 56 | |
| 51 // Stores data relevant to the statistics of writing and reading entire | 57 // Stores data relevant to the statistics of writing and reading entire | 
| 52 // certificate chains using DiskBasedCertCache. |num_pending_ops| is the number | 58 // certificate chains using DiskBasedCertCache. |num_pending_ops| is the number | 
| 53 // of certificates in the chain that have pending operations in the | 59 // of certificates in the chain that have pending operations in the | 
| 54 // DiskBasedCertCache. |start_time| is the time that the read and write | 60 // DiskBasedCertCache. |start_time| is the time that the read and write | 
| 55 // commands began being issued to the DiskBasedCertCache. | 61 // commands began being issued to the DiskBasedCertCache. | 
| 56 // TODO(brandonsalmon): Remove this when it is no longer necessary to | 62 // TODO(brandonsalmon): Remove this when it is no longer necessary to | 
| 57 // collect data. | 63 // collect data. | 
| 58 class SharedChainData : public base::RefCounted<SharedChainData> { | 64 class SharedChainData : public base::RefCounted<SharedChainData> { | 
| 59 public: | 65 public: | 
| 60 SharedChainData(int num_ops, TimeTicks start) | 66 SharedChainData(int num_ops, TimeTicks start) | 
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 225 | 231 | 
| 226 void RecordNoStoreHeaderHistogram(int load_flags, | 232 void RecordNoStoreHeaderHistogram(int load_flags, | 
| 227 const net::HttpResponseInfo* response) { | 233 const net::HttpResponseInfo* response) { | 
| 228 if (load_flags & net::LOAD_MAIN_FRAME) { | 234 if (load_flags & net::LOAD_MAIN_FRAME) { | 
| 229 UMA_HISTOGRAM_BOOLEAN( | 235 UMA_HISTOGRAM_BOOLEAN( | 
| 230 "Net.MainFrameNoStore", | 236 "Net.MainFrameNoStore", | 
| 231 response->headers->HasHeaderValue("cache-control", "no-store")); | 237 response->headers->HasHeaderValue("cache-control", "no-store")); | 
| 232 } | 238 } | 
| 233 } | 239 } | 
| 234 | 240 | 
| 241 // TODO(ricea): Move this to a more appropriate home. Also, this is closely | |
| 
rvargas (doing something else)
2014/07/24 00:54:06
I think we should move this to http_response_heade
 
Adam Rice
2014/07/28 11:11:13
Done.
 | |
| 242 // based on HttpResponseHeaders::GetMaxAgeValue so they should probably share | |
| 243 // implementation. | |
| 244 bool GetStaleWhileRevalidateValue(const net::HttpResponseHeaders& headers, | |
| 245 TimeDelta* result) { | |
| 246 const std::string name = "cache-control"; | |
| 
rvargas (doing something else)
2014/07/24 00:54:06
nit: remove const and use constructor initializati
 
Adam Rice
2014/07/28 11:11:13
Done.
 | |
| 247 std::string value; | |
| 248 | |
| 249 const char kStaleWhileRevalidatePrefix[] = "stale-while-revalidate="; | |
| 250 const size_t kStaleWhileRevalidatePrefixLen = | |
| 251 arraysize(kStaleWhileRevalidatePrefix) - 1; | |
| 252 | |
| 253 void* iter = NULL; | |
| 254 while (headers.EnumerateHeader(&iter, name, &value)) { | |
| 255 if (value.size() > kStaleWhileRevalidatePrefixLen && | |
| 256 LowerCaseEqualsASCII(value.begin(), | |
| 257 value.begin() + kStaleWhileRevalidatePrefixLen, | |
| 258 kStaleWhileRevalidatePrefix)) { | |
| 259 int64 seconds = 0; | |
| 260 const base::StringPiece parameter = base::StringPiece( | |
| 261 value.begin() + kStaleWhileRevalidatePrefixLen, value.end()); | |
| 262 if (!base::StringToInt64(parameter, &seconds) || seconds < 0) | |
| 263 continue; | |
| 264 *result = TimeDelta::FromSeconds(seconds); | |
| 265 return true; | |
| 266 } | |
| 267 } | |
| 268 | |
| 269 return false; | |
| 270 } | |
| 271 | |
| 235 } // namespace | 272 } // namespace | 
| 236 | 273 | 
| 237 namespace net { | 274 namespace net { | 
| 238 | 275 | 
| 239 struct HeaderNameAndValue { | 276 struct HeaderNameAndValue { | 
| 240 const char* name; | 277 const char* name; | 
| 241 const char* value; | 278 const char* value; | 
| 242 }; | 279 }; | 
| 243 | 280 | 
| 244 // If the request includes one of these request headers, then avoid caching | 281 // If the request includes one of these request headers, then avoid caching | 
| (...skipping 2005 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2250 if (!partial_.get()) { | 2287 if (!partial_.get()) { | 
| 2251 // Need to customize the request, so this forces us to allocate :( | 2288 // Need to customize the request, so this forces us to allocate :( | 
| 2252 custom_request_.reset(new HttpRequestInfo(*request_)); | 2289 custom_request_.reset(new HttpRequestInfo(*request_)); | 
| 2253 request_ = custom_request_.get(); | 2290 request_ = custom_request_.get(); | 
| 2254 } | 2291 } | 
| 2255 DCHECK(custom_request_.get()); | 2292 DCHECK(custom_request_.get()); | 
| 2256 | 2293 | 
| 2257 bool use_if_range = partial_.get() && !partial_->IsCurrentRangeCached() && | 2294 bool use_if_range = partial_.get() && !partial_->IsCurrentRangeCached() && | 
| 2258 !invalid_range_; | 2295 !invalid_range_; | 
| 2259 | 2296 | 
| 2297 if (!use_if_range && request_->privacy_mode != PRIVACY_MODE_ENABLED) { | |
| 2298 // stale-while-revalidate is not useful when we only have a partial response | |
| 2299 // cached, so don't set the header in that case. | |
| 2300 // Also don't send the header when privacy mode is enabled, to avoid | |
| 2301 // accidentally fingerprinting the user. | |
| 2302 base::TimeDelta stale_while_revalidate; | |
| 2303 if (GetStaleWhileRevalidateValue(*response_.headers, | |
| 2304 &stale_while_revalidate)) { | |
| 2305 base::TimeDelta max_age = | |
| 2306 response_.headers->GetFreshnessLifetime(response_.response_time); | |
| 2307 base::TimeDelta current_age = response_.headers->GetCurrentAge( | |
| 2308 response_.request_time, response_.response_time, Time::Now()); | |
| 2309 | |
| 2310 custom_request_->extra_headers.SetHeader( | |
| 
rvargas (doing something else)
2014/07/24 00:54:06
We should probably send the header only when stale
 
Adam Rice
2014/07/28 11:11:13
I think this would probably make analysis too diff
 | |
| 2311 kFreshnessHeader, | |
| 2312 base::StringPrintf("max-age=%" PRId64 | |
| 2313 ",stale-while-revalidate=%" PRId64 ",age=%" PRId64, | |
| 2314 max_age.InSeconds(), | |
| 2315 stale_while_revalidate.InSeconds(), | |
| 2316 current_age.InSeconds())); | |
| 2317 } | |
| 2318 } | |
| 2319 | |
| 2260 if (!etag_value.empty()) { | 2320 if (!etag_value.empty()) { | 
| 2261 if (use_if_range) { | 2321 if (use_if_range) { | 
| 2262 // We don't want to switch to WRITE mode if we don't have this block of a | 2322 // We don't want to switch to WRITE mode if we don't have this block of a | 
| 2263 // byte-range request because we may have other parts cached. | 2323 // byte-range request because we may have other parts cached. | 
| 2264 custom_request_->extra_headers.SetHeader( | 2324 custom_request_->extra_headers.SetHeader( | 
| 2265 HttpRequestHeaders::kIfRange, etag_value); | 2325 HttpRequestHeaders::kIfRange, etag_value); | 
| 2266 } else { | 2326 } else { | 
| 2267 custom_request_->extra_headers.SetHeader( | 2327 custom_request_->extra_headers.SetHeader( | 
| 2268 HttpRequestHeaders::kIfNoneMatch, etag_value); | 2328 HttpRequestHeaders::kIfNoneMatch, etag_value); | 
| 2269 } | 2329 } | 
| (...skipping 476 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2746 default: | 2806 default: | 
| 2747 NOTREACHED(); | 2807 NOTREACHED(); | 
| 2748 } | 2808 } | 
| 2749 } | 2809 } | 
| 2750 | 2810 | 
| 2751 void HttpCache::Transaction::OnIOComplete(int result) { | 2811 void HttpCache::Transaction::OnIOComplete(int result) { | 
| 2752 DoLoop(result); | 2812 DoLoop(result); | 
| 2753 } | 2813 } | 
| 2754 | 2814 | 
| 2755 } // namespace net | 2815 } // namespace net | 
| OLD | NEW |