chorme源码 判断http缓存是否有效

50 阅读3分钟

计算资源的有效时间

HttpResponseHeaders::GetFreshnessLifetimes(const Time& response_time) const {
  FreshnessLifetimes lifetimes;
  
  if (HasHeaderValue("cache-control", "no-cache") ||
      HasHeaderValue("cache-control", "no-store") ||
      HasHeaderValue("pragma", "no-cache")) {
    return lifetimes;
  }

  bool must_revalidate = HasHeaderValue("cache-control", "must-revalidate");

  lifetimes.staleness =
      must_revalidate
          ? base::TimeDelta()
          : GetStaleWhileRevalidateValue().value_or(base::TimeDelta());


  std::optional<base::TimeDelta> max_age_value = GetMaxAgeValue();
  if (max_age_value) {
    lifetimes.freshness = max_age_value.value();
    return lifetimes;
  }

  Time date_value = GetDateValue().value_or(response_time);

  std::optional<Time> expires_value = GetExpiresValue();
  if (expires_value) {
    // The expires value can be a date in the past!
    if (expires_value > date_value) {
      lifetimes.freshness = expires_value.value() - date_value;
      return lifetimes;
    }

    DCHECK_EQ(base::TimeDelta(), lifetimes.freshness);
    return lifetimes;
  }

1、对于设置了"cache-control":"no-cache""cache-control":"no-store""pragma":"no-cache"请求头的资源,有效期为0

2、获取资源过期后仍可使用的时间

3、如果存在max-age,有效期为max-age的值

4、如果存在Expires,有效期为Expires - Date

计算资源的已缓存时间

base::TimeDelta HttpResponseHeaders::GetCurrentAge(
    const Time& request_time,
    const Time& response_time,
    const Time& current_time) const {
  // If there is no Date header, then assume that the server response was
  // generated at the time when we received the response.
  Time date_value = GetDateValue().value_or(response_time);

  // If there is no Age header, then assume age is zero.
  base::TimeDelta age_value = GetAgeValue().value_or(base::TimeDelta());

  base::TimeDelta apparent_age =
      std::max(base::TimeDelta(), response_time - date_value);
  base::TimeDelta response_delay = response_time - request_time;
  base::TimeDelta corrected_age_value = age_value + response_delay;
  base::TimeDelta corrected_initial_age =
      std::max(apparent_age, corrected_age_value);
  base::TimeDelta resident_time = current_time - response_time;
  base::TimeDelta current_age = corrected_initial_age + resident_time;

  return current_age;
}

1、已缓存时间1:响应时间 - Date和1微秒取最大值

2、已缓存时间2:响应时间 - 请求时间 + 缓存服务器已缓存时间

3、(当前时间-响应时间) + (时间1和时间2的较大值)

响应是否过期,确定缓存验证方式

ValidationType HttpResponseHeaders::RequiresValidation(
    const Time& request_time,
    const Time& response_time,
    const Time& current_time) const {
  FreshnessLifetimes lifetimes = GetFreshnessLifetimes(response_time);
  if (lifetimes.freshness.is_zero() && lifetimes.staleness.is_zero())
    return VALIDATION_SYNCHRONOUS;

  base::TimeDelta age =
      GetCurrentAge(request_time, response_time, current_time);

  if (lifetimes.freshness > age)
    return VALIDATION_NONE;

  if (lifetimes.freshness + lifetimes.staleness > age)
    return VALIDATION_ASYNCHRONOUS;

  return VALIDATION_SYNCHRONOUS;
}

1、如果资源有效期是0并且过期后能使用时间为0,需要同步验证

2、如果资源的已缓存时间小于资源的有效时间,可以使用缓存

3、如果资源的有效期 + 资源过期还能使用时间 > 资源缓存时间,可以进行异步的验证

4、上面不匹配,需要进行同步验证

  • VALIDATION_NONE 代表资源缓存可以使用,不需要进行验证
  • VALIDATION_SYNCHRONOUS 代表资源已过期,需要同步在源服务器验证资源是否过期
  • VALIDATION_ASYNCHRONOUS 代表资源已过期,但是可以先使用缓存,在验证更新缓存
ValidationType HttpCache::Transaction::RequiresValidation() {
  

  if (!(effective_load_flags_ & LOAD_SKIP_VARY_CHECK) &&
      response_.vary_data.is_valid() &&
      !response_.vary_data.MatchesRequest(*request_,
                                          *response_.headers.get())) {
    vary_mismatch_ = true;
    return VALIDATION_SYNCHRONOUS;
  }

  if (method_ == "PUT" || method_ == "DELETE" || method_ == "PATCH") {
    return VALIDATION_SYNCHRONOUS;
  }

  bool validate_flag = effective_load_flags_ & LOAD_VALIDATE_CACHE;

  ValidationType validation_required_by_headers =
      validate_flag ? VALIDATION_SYNCHRONOUS
                    : response_.headers->RequiresValidation(
                          response_.request_time, response_.response_time,
                          cache_->clock_->Now());

  if (validation_required_by_headers == VALIDATION_ASYNCHRONOUS) {
    // Asynchronous revalidation is only supported for GET methods.
    if (request_->method != "GET") {
      return VALIDATION_SYNCHRONOUS;
    }

    // If the timeout on the staleness revalidation is set don't hand out
    // a resource that hasn't been async validated.
    if (!response_.stale_revalidate_timeout.is_null() &&
        response_.stale_revalidate_timeout < cache_->clock_->Now()) {
      return VALIDATION_SYNCHRONOUS;
    }
  }

  return validation_required_by_headers;
}

1、判断请求的vary是否一致,如果vary不一致,需要进行同步验证

2、PUT、DELETE、PATCH请求,需要进行同步验证

3、如果是异步验证并且请求方法不是get,转为同步验证,如果设置了接受已过期的资源,但是已经超时,转为同步验证

4、使用validation_required_by_headers的值