HttpTransact::calculate_document_freshness_limit(State *s, HTTPHdr *response, time_t response_date, bool *heuristic)
{
  bool expires_set, date_set, last_modified_set;
  time_t date_value, expires_value, last_modified_value;
  MgmtInt min_freshness_bounds, max_freshness_bounds;
  int freshness_limit = 0;
  uint32_t cc_mask = response->get_cooked_cc_mask();

  *heuristic = false;

  if (cc_mask & (MIME_COOKED_MASK_CC_S_MAXAGE | MIME_COOKED_MASK_CC_MAX_AGE)) {
    if (cc_mask & MIME_COOKED_MASK_CC_S_MAXAGE) {
      freshness_limit = (int) response->get_cooked_cc_s_maxage();
      DebugTxn("http_match", "calculate_document_freshness_limit --- s_max_age set, freshness_limit = %d", freshness_limit);
    } else if (cc_mask & MIME_COOKED_MASK_CC_MAX_AGE) {
      freshness_limit = (int) response->get_cooked_cc_max_age();
      DebugTxn("http_match", "calculate_document_freshness_limit --- max_age set, freshness_limit = %d", freshness_limit);
    }
    freshness_limit = min(max(0, freshness_limit), NUM_SECONDS_IN_ONE_YEAR);
  } else {
    date_set = last_modified_set = false;

    if (s->plugin_set_expire_time != UNDEFINED_TIME) {
      expires_set = true;
      expires_value = s->plugin_set_expire_time;
    } else {
      expires_set = (response->presence(MIME_PRESENCE_EXPIRES) != 0);
      expires_value = response->get_expires();
    }

    date_value = response_date;
    if (date_value > 0) {
      date_set = true;
    } else {
      date_value = s->request_sent_time;
      DebugTxn("http_match",
               "calculate_document_freshness_limit --- Expires header = %" PRId64 " no date, using sent time %" PRId64,
               (int64_t)expires_value, (int64_t)date_value);
    }
    ink_assert(date_value > 0);

    // Getting the cache_sm object
    HttpCacheSM & cache_sm = s->state_machine->get_cache_sm();

    //Bypassing if loop to set freshness_limit to heuristic value
    if (expires_set && !cache_sm.is_readwhilewrite_inprogress()) {
      if (expires_value == UNDEFINED_TIME || expires_value <= date_value) {
        expires_value = date_value;
        DebugTxn("http_match", "calculate_document_freshness_limit --- no expires, using date %" PRId64,
                 (int64_t)expires_value);
      }
      freshness_limit = (int) (expires_value - date_value);

      DebugTxn("http_match",
               "calculate_document_freshness_limit --- Expires: %" PRId64 ", Date: %" PRId64 ", freshness_limit = %d",
               (int64_t)expires_value, (int64_t)date_value, freshness_limit);

      freshness_limit = min(max(0, freshness_limit), NUM_SECONDS_IN_ONE_YEAR);
    } else {
      last_modified_value = 0;
      if (response->presence(MIME_PRESENCE_LAST_MODIFIED)) {
        last_modified_set = true;
        last_modified_value = response->get_last_modified();
        DebugTxn("http_match", "calculate_document_freshness_limit --- Last Modified header = %" PRId64,
                 (int64_t)last_modified_value);

        if (last_modified_value == UNDEFINED_TIME) {
          last_modified_set = false;
        } else if (last_modified_value > date_value) {
          last_modified_value = date_value;
          DebugTxn("http_match", "calculate_document_freshness_limit --- no last-modified, using sent time %" PRId64,
                   (int64_t)last_modified_value);
        }
      }

      *heuristic = true;
      if (date_set && last_modified_set) {
        MgmtFloat f = s->txn_conf->cache_heuristic_lm_factor;
        ink_assert((f >= 0.0) && (f <= 1.0));
        ink_time_t time_since_last_modify = date_value - last_modified_value;
        int h_freshness = (int) (time_since_last_modify * f);
        freshness_limit = max(h_freshness, 0);
        DebugTxn("http_match", "calculate_document_freshness_limit --- heuristic: date=%" PRId64 ", lm=%" PRId64
                 ", time_since_last_modify=%"  PRId64 ", f=%g, freshness_limit = %d",
                 (int64_t)date_value, (int64_t)last_modified_value, (int64_t)time_since_last_modify,
              f, freshness_limit);
      } else {
        freshness_limit = s->txn_conf->cache_heuristic_min_lifetime;
        DebugTxn("http_match", "calculate_document_freshness_limit --- heuristic: freshness_limit = %d", freshness_limit);
      }
    }
  }

  // The freshness limit must always fall within the min and max guaranteed bounds.
  min_freshness_bounds = max((MgmtInt)0, s->txn_conf->cache_guaranteed_min_lifetime);
  max_freshness_bounds = min((MgmtInt)NUM_SECONDS_IN_ONE_YEAR, s->txn_conf->cache_guaranteed_max_lifetime);

  // Heuristic freshness can be more strict.
  if (*heuristic) {
    min_freshness_bounds = max(min_freshness_bounds, s->txn_conf->cache_heuristic_min_lifetime);
    max_freshness_bounds = min(max_freshness_bounds, s->txn_conf->cache_heuristic_max_lifetime);
  }
  // Now clip the freshness limit.
  if (freshness_limit > max_freshness_bounds)
    freshness_limit = max_freshness_bounds;
  if (freshness_limit < min_freshness_bounds)
    freshness_limit = min_freshness_bounds;

  DebugTxn("http_match", "calculate_document_freshness_limit --- final freshness_limit = %d", freshness_limit);

  return (freshness_limit);
}
HttpTransact::calculate_document_freshness_limit(State *s, HTTPHdr *response, time_t response_date, bool *heuristic)
{
  bool expires_set, date_set, last_modified_set;
  time_t date_value, expires_value, last_modified_value;
  MgmtInt min_freshness_bounds, max_freshness_bounds;
  int freshness_limit = 0;
  uint32_t cc_mask = response->get_cooked_cc_mask();

  *heuristic = false;

  if (cc_mask & (MIME_COOKED_MASK_CC_S_MAXAGE | MIME_COOKED_MASK_CC_MAX_AGE)) {
    if (cc_mask & MIME_COOKED_MASK_CC_S_MAXAGE) {
      freshness_limit = (int) response->get_cooked_cc_s_maxage();
      DebugTxn("http_match", "calculate_document_freshness_limit --- s_max_age set, freshness_limit = %d", freshness_limit);
    } else if (cc_mask & MIME_COOKED_MASK_CC_MAX_AGE) {
      freshness_limit = (int) response->get_cooked_cc_max_age();
      DebugTxn("http_match", "calculate_document_freshness_limit --- max_age set, freshness_limit = %d", freshness_limit);
    }
    freshness_limit = min(max(0, freshness_limit), NUM_SECONDS_IN_ONE_YEAR);
  } else {
    date_set = last_modified_set = false;

    if (s->plugin_set_expire_time != UNDEFINED_TIME) {
      expires_set = true;
      expires_value = s->plugin_set_expire_time;
    } else {
      expires_set = (response->presence(MIME_PRESENCE_EXPIRES) != 0);
      expires_value = response->get_expires();
    }

    date_value = response_date;
    if (date_value > 0) {
      date_set = true;
    } else {
      date_value = s->request_sent_time;
      DebugTxn("http_match",
               "calculate_document_freshness_limit --- Expires header = %" PRId64 " no date, using sent time %" PRId64,
               (int64_t)expires_value, (int64_t)date_value);
    }
    ink_assert(date_value > 0);

     
    HttpCacheSM & cache_sm = s->state_machine->get_cache_sm();

     
    if (expires_set && !cache_sm.is_readwhilewrite_inprogress()) {
      if (expires_value == UNDEFINED_TIME || expires_value <= date_value) {
        expires_value = date_value;
        DebugTxn("http_match", "calculate_document_freshness_limit --- no expires, using date %" PRId64,
                 (int64_t)expires_value);
      }
      freshness_limit = (int) (expires_value - date_value);

      DebugTxn("http_match",
               "calculate_document_freshness_limit --- Expires: %" PRId64 ", Date: %" PRId64 ", freshness_limit = %d",
               (int64_t)expires_value, (int64_t)date_value, freshness_limit);

      freshness_limit = min(max(0, freshness_limit), NUM_SECONDS_IN_ONE_YEAR);
    } else {
      last_modified_value = 0;
      if (response->presence(MIME_PRESENCE_LAST_MODIFIED)) {
        last_modified_set = true;
        last_modified_value = response->get_last_modified();
        DebugTxn("http_match", "calculate_document_freshness_limit --- Last Modified header = %" PRId64,
                 (int64_t)last_modified_value);

        if (last_modified_value == UNDEFINED_TIME) {
          last_modified_set = false;
        } else if (last_modified_value > date_value) {
          last_modified_value = date_value;
          DebugTxn("http_match", "calculate_document_freshness_limit --- no last-modified, using sent time %" PRId64,
                   (int64_t)last_modified_value);
        }
      }

      *heuristic = true;
      if (date_set && last_modified_set) {
        MgmtFloat f = s->txn_conf->cache_heuristic_lm_factor;
        ink_assert((f >= 0.0) && (f <= 1.0));
        ink_time_t time_since_last_modify = date_value - last_modified_value;
        int h_freshness = (int) (time_since_last_modify * f);
        freshness_limit = max(h_freshness, 0);
        DebugTxn("http_match", "calculate_document_freshness_limit --- heuristic: date=%" PRId64 ", lm=%" PRId64
                 ", time_since_last_modify=%"  PRId64 ", f=%g, freshness_limit = %d",
                 (int64_t)date_value, (int64_t)last_modified_value, (int64_t)time_since_last_modify,
              f, freshness_limit);
      } else {
        freshness_limit = s->txn_conf->cache_heuristic_min_lifetime;
        DebugTxn("http_match", "calculate_document_freshness_limit --- heuristic: freshness_limit = %d", freshness_limit);
      }
    }
  }

   
  min_freshness_bounds = max((MgmtInt)0, s->txn_conf->cache_guaranteed_min_lifetime);
  max_freshness_bounds = min((MgmtInt)NUM_SECONDS_IN_ONE_YEAR, s->txn_conf->cache_guaranteed_max_lifetime);

   
  if (*heuristic) {
    min_freshness_bounds = max(min_freshness_bounds, s->txn_conf->cache_heuristic_min_lifetime);
    max_freshness_bounds = min(max_freshness_bounds, s->txn_conf->cache_heuristic_max_lifetime);
  }
   
  if (freshness_limit > max_freshness_bounds)
    freshness_limit = max_freshness_bounds;
  if (freshness_limit < min_freshness_bounds)
    freshness_limit = min_freshness_bounds;

  DebugTxn("http_match", "calculate_document_freshness_limit --- final freshness_limit = %d", freshness_limit);

  return (freshness_limit);
}