HttpTransact::what_is_document_freshness(State *s, HTTPHdr* client_request, HTTPHdr* cached_obj_response)
{
  bool heuristic, do_revalidate = false;
  int age_limit;
  // These aren't used.
  //HTTPValCacheControl *cc;
  //const char *cc_val;
  int fresh_limit;
  ink_time_t current_age, response_date;;
  uint32_t cc_mask, cooked_cc_mask;
  uint32_t os_specifies_revalidate;

  //////////////////////////////////////////////////////
  // If config file has a ttl-in-cache field set,     //
  // it has priority over any other http headers and  //
  // other configuration parameters.                  //
  //////////////////////////////////////////////////////
  if (s->cache_control.ttl_in_cache > 0) {
    // what matters if ttl is set is not the age of the document
    // but for how long it has been stored in the cache (resident time)
    int resident_time = s->current.now - s->response_received_time;

    DebugTxn("http_match", "[..._document_freshness] ttl-in-cache = %d, resident time = %d", s->cache_control.ttl_in_cache,
          resident_time);
    if (resident_time > s->cache_control.ttl_in_cache) {
      return (FRESHNESS_STALE);
    } else {
      return (FRESHNESS_FRESH);
    }
  }


  cooked_cc_mask = cached_obj_response->get_cooked_cc_mask();
  os_specifies_revalidate = cooked_cc_mask &
    (MIME_COOKED_MASK_CC_MUST_REVALIDATE | MIME_COOKED_MASK_CC_PROXY_REVALIDATE);
  cc_mask = MIME_COOKED_MASK_CC_NEED_REVALIDATE_ONCE;

  // Check to see if the server forces revalidation

  if ((cooked_cc_mask & cc_mask) && s->cache_control.revalidate_after <= 0) {
    DebugTxn("http_match", "[what_is_document_freshness] document stale due to " "server must-revalidate");
    return FRESHNESS_STALE;
  }

  response_date = cached_obj_response->get_date();
  fresh_limit = calculate_document_freshness_limit(s, cached_obj_response, response_date, &heuristic);
  ink_assert(fresh_limit >= 0);

  // Fuzz the freshness to prevent too many revalidates to popular
  //  documents at the same time
  if (s->txn_conf->freshness_fuzz_time >= 0) {
    fresh_limit = fresh_limit - calculate_freshness_fuzz(s, fresh_limit);
    fresh_limit = max(0, fresh_limit);
    fresh_limit = min(NUM_SECONDS_IN_ONE_YEAR, fresh_limit);
  }

  current_age = HttpTransactHeaders::calculate_document_age(s->request_sent_time, s->response_received_time,
                                                            cached_obj_response, response_date, s->current.now);

  // Overflow ?
  if (current_age < 0)
    current_age = NUM_SECONDS_IN_ONE_YEAR;  // TODO: Should we make a new "max age" define?
  else
    current_age = min((time_t)NUM_SECONDS_IN_ONE_YEAR, current_age);

  DebugTxn("http_match", "[what_is_document_freshness] fresh_limit:  %d  current_age: %" PRId64,
           fresh_limit, (int64_t)current_age);

  /////////////////////////////////////////////////////////
  // did the admin override the expiration calculations? //
  // (used only for http).                               //
  /////////////////////////////////////////////////////////
  ink_assert(client_request == &s->hdr_info.client_request);

  if (s->txn_conf->cache_when_to_revalidate == 0) {
    ;
    // Compute how fresh below
  } else if (client_request->url_get()->scheme_get_wksidx() == URL_WKSIDX_HTTP) {
    switch (s->txn_conf->cache_when_to_revalidate) {
    case 1:                    // Stale if heuristic
      if (heuristic) {
        DebugTxn("http_match", "[what_is_document_freshness] config requires FRESHNESS_STALE because heuristic calculation");
        return (FRESHNESS_STALE);
      }
      break;
    case 2:                    // Always stale
      DebugTxn("http_match", "[what_is_document_freshness] config " "specifies always FRESHNESS_STALE");
      return (FRESHNESS_STALE);
    case 3:                    // Never stale
      DebugTxn("http_match", "[what_is_document_freshness] config " "specifies always FRESHNESS_FRESH");
      return (FRESHNESS_FRESH);
    case 4:                    // Stale if IMS
      if (client_request->presence(MIME_PRESENCE_IF_MODIFIED_SINCE)) {
        DebugTxn("http_match", "[what_is_document_freshness] config " "specifies FRESHNESS_STALE if IMS present");
        return (FRESHNESS_STALE);
      }
    default:                   // Bad config, ignore
      break;
    }
  }
  //////////////////////////////////////////////////////////////////////
  // the normal expiration policy allows serving a doc from cache if: //
  //     basic:          (current_age <= fresh_limit)                 //
  //                                                                  //
  // this can be modified by client Cache-Control headers:            //
  //     max-age:        (current_age <= max_age)                     //
  //     min-fresh:      (current_age <= fresh_limit - min_fresh)     //
  //     max-stale:      (current_age <= fresh_limit + max_stale)     //
  //////////////////////////////////////////////////////////////////////
  age_limit = fresh_limit;      // basic constraint
  DebugTxn("http_match", "[..._document_freshness] initial age limit: %d", age_limit);

  cooked_cc_mask = client_request->get_cooked_cc_mask();
  cc_mask = (MIME_COOKED_MASK_CC_MAX_STALE | MIME_COOKED_MASK_CC_MIN_FRESH | MIME_COOKED_MASK_CC_MAX_AGE);
  if (cooked_cc_mask & cc_mask) {
    /////////////////////////////////////////////////
    // if max-stale set, relax the freshness limit //
    /////////////////////////////////////////////////
    if (cooked_cc_mask & MIME_COOKED_MASK_CC_MAX_STALE) {
      if (os_specifies_revalidate) {
        DebugTxn("http_match", "[...document_freshness] OS specifies revalidation; "
              "ignoring client's max-stale request...");
      } else {
        int max_stale_val = client_request->get_cooked_cc_max_stale();

        if (max_stale_val != INT_MAX)
          age_limit += max_stale_val;
        else
          age_limit = max_stale_val;
        DebugTxn("http_match", "[..._document_freshness] max-stale set, age limit: %d", age_limit);
      }
    }
    /////////////////////////////////////////////////////
    // if min-fresh set, constrain the freshness limit //
    /////////////////////////////////////////////////////
    if (cooked_cc_mask & MIME_COOKED_MASK_CC_MIN_FRESH) {
      age_limit = min(age_limit, fresh_limit - client_request->get_cooked_cc_min_fresh());
      DebugTxn("http_match", "[..._document_freshness] min_fresh set, age limit: %d", age_limit);
    }
    ///////////////////////////////////////////////////
    // if max-age set, constrain the freshness limit //
    ///////////////////////////////////////////////////
    if (!s->cache_control.ignore_client_cc_max_age && (cooked_cc_mask & MIME_COOKED_MASK_CC_MAX_AGE)) {
      int age_val = client_request->get_cooked_cc_max_age();
      if (age_val == 0)
        do_revalidate = true;
      age_limit = min(age_limit, age_val);
      DebugTxn("http_match", "[..._document_freshness] min_fresh set, age limit: %d", age_limit);
    }
  }
  /////////////////////////////////////////////////////////
  // config file may have a "revalidate_after" field set //
  /////////////////////////////////////////////////////////
  // bug fix changed ">0" to ">=0"
  if (s->cache_control.revalidate_after >= 0) {
    // if we want the minimum of the already-computed age_limit and revalidate_after
//      age_limit = mine(age_limit, s->cache_control.revalidate_after);

    // if instead the revalidate_after overrides all other variables
    age_limit = s->cache_control.revalidate_after;

    DebugTxn("http_match", "[..._document_freshness] revalidate_after set, age limit: %d", age_limit);
  }

  DebugTxn("http_match", "document_freshness --- current_age = %" PRId64, (int64_t)current_age);
  DebugTxn("http_match", "document_freshness --- age_limit   = %d", age_limit);
  DebugTxn("http_match", "document_freshness --- fresh_limit = %d", fresh_limit);
  DebugTxn("http_seq", "document_freshness --- current_age = %" PRId64, (int64_t)current_age);
  DebugTxn("http_seq", "document_freshness --- age_limit   = %d", age_limit);
  DebugTxn("http_seq", "document_freshness --- fresh_limit = %d", fresh_limit);
  ///////////////////////////////////////////
  // now, see if the age is "fresh enough" //
  ///////////////////////////////////////////

  if (do_revalidate || current_age > age_limit) { // client-modified limit
    DebugTxn("http_match", "[..._document_freshness] document needs revalidate/too old; "
            "returning FRESHNESS_STALE");
    return (FRESHNESS_STALE);
  } else if (current_age > fresh_limit) {  // original limit
    if (os_specifies_revalidate) {
      DebugTxn("http_match", "[..._document_freshness] document is stale and OS specifies revalidation; "
              "returning FRESHNESS_STALE");
      return (FRESHNESS_STALE);
    }
    DebugTxn("http_match", "[..._document_freshness] document is stale but no revalidation explicitly required; "
            "returning FRESHNESS_WARNING");
    return (FRESHNESS_WARNING);
  } else {
    DebugTxn("http_match", "[..._document_freshness] document is fresh; returning FRESHNESS_FRESH");
    return (FRESHNESS_FRESH);
  }
}
HttpTransact::what_is_document_freshness(State *s, HTTPHdr* client_request, HTTPHdr* cached_obj_response)
{
  bool heuristic, do_revalidate = false;
  int age_limit;
   
   
   
  int fresh_limit;
  ink_time_t current_age, response_date;;
  uint32_t cc_mask, cooked_cc_mask;
  uint32_t os_specifies_revalidate;

   
   
   
   
   
  if (s->cache_control.ttl_in_cache > 0) {
     
     
    int resident_time = s->current.now - s->response_received_time;

    DebugTxn("http_match", "[..._document_freshness] ttl-in-cache = %d, resident time = %d", s->cache_control.ttl_in_cache,
          resident_time);
    if (resident_time > s->cache_control.ttl_in_cache) {
      return (FRESHNESS_STALE);
    } else {
      return (FRESHNESS_FRESH);
    }
  }


  cooked_cc_mask = cached_obj_response->get_cooked_cc_mask();
  os_specifies_revalidate = cooked_cc_mask &
    (MIME_COOKED_MASK_CC_MUST_REVALIDATE | MIME_COOKED_MASK_CC_PROXY_REVALIDATE);
  cc_mask = MIME_COOKED_MASK_CC_NEED_REVALIDATE_ONCE;

   

  if ((cooked_cc_mask & cc_mask) && s->cache_control.revalidate_after <= 0) {
    DebugTxn("http_match", "[what_is_document_freshness] document stale due to " "server must-revalidate");
    return FRESHNESS_STALE;
  }

  response_date = cached_obj_response->get_date();
  fresh_limit = calculate_document_freshness_limit(s, cached_obj_response, response_date, &heuristic);
  ink_assert(fresh_limit >= 0);

   
   
  if (s->txn_conf->freshness_fuzz_time >= 0) {
    fresh_limit = fresh_limit - calculate_freshness_fuzz(s, fresh_limit);
    fresh_limit = max(0, fresh_limit);
    fresh_limit = min(NUM_SECONDS_IN_ONE_YEAR, fresh_limit);
  }

  current_age = HttpTransactHeaders::calculate_document_age(s->request_sent_time, s->response_received_time,
                                                            cached_obj_response, response_date, s->current.now);

   
  if (current_age < 0)
    current_age = NUM_SECONDS_IN_ONE_YEAR;   
  else
    current_age = min((time_t)NUM_SECONDS_IN_ONE_YEAR, current_age);

  DebugTxn("http_match", "[what_is_document_freshness] fresh_limit:  %d  current_age: %" PRId64,
           fresh_limit, (int64_t)current_age);

   
   
   
   
  ink_assert(client_request == &s->hdr_info.client_request);

  if (s->txn_conf->cache_when_to_revalidate == 0) {
    ;
     
  } else if (client_request->url_get()->scheme_get_wksidx() == URL_WKSIDX_HTTP) {
    switch (s->txn_conf->cache_when_to_revalidate) {
    case 1:                     
      if (heuristic) {
        DebugTxn("http_match", "[what_is_document_freshness] config requires FRESHNESS_STALE because heuristic calculation");
        return (FRESHNESS_STALE);
      }
      break;
    case 2:                     
      DebugTxn("http_match", "[what_is_document_freshness] config " "specifies always FRESHNESS_STALE");
      return (FRESHNESS_STALE);
    case 3:                     
      DebugTxn("http_match", "[what_is_document_freshness] config " "specifies always FRESHNESS_FRESH");
      return (FRESHNESS_FRESH);
    case 4:                     
      if (client_request->presence(MIME_PRESENCE_IF_MODIFIED_SINCE)) {
        DebugTxn("http_match", "[what_is_document_freshness] config " "specifies FRESHNESS_STALE if IMS present");
        return (FRESHNESS_STALE);
      }
    default:                    
      break;
    }
  }
   
   
   
   
   
   
   
   
   
  age_limit = fresh_limit;       
  DebugTxn("http_match", "[..._document_freshness] initial age limit: %d", age_limit);

  cooked_cc_mask = client_request->get_cooked_cc_mask();
  cc_mask = (MIME_COOKED_MASK_CC_MAX_STALE | MIME_COOKED_MASK_CC_MIN_FRESH | MIME_COOKED_MASK_CC_MAX_AGE);
  if (cooked_cc_mask & cc_mask) {
     
     
     
    if (cooked_cc_mask & MIME_COOKED_MASK_CC_MAX_STALE) {
      if (os_specifies_revalidate) {
        DebugTxn("http_match", "[...document_freshness] OS specifies revalidation; "
              "ignoring client's max-stale request...");
      } else {
        int max_stale_val = client_request->get_cooked_cc_max_stale();

        if (max_stale_val != INT_MAX)
          age_limit += max_stale_val;
        else
          age_limit = max_stale_val;
        DebugTxn("http_match", "[..._document_freshness] max-stale set, age limit: %d", age_limit);
      }
    }
     
     
     
    if (cooked_cc_mask & MIME_COOKED_MASK_CC_MIN_FRESH) {
      age_limit = min(age_limit, fresh_limit - client_request->get_cooked_cc_min_fresh());
      DebugTxn("http_match", "[..._document_freshness] min_fresh set, age limit: %d", age_limit);
    }
     
     
     
    if (!s->cache_control.ignore_client_cc_max_age && (cooked_cc_mask & MIME_COOKED_MASK_CC_MAX_AGE)) {
      int age_val = client_request->get_cooked_cc_max_age();
      if (age_val == 0)
        do_revalidate = true;
      age_limit = min(age_limit, age_val);
      DebugTxn("http_match", "[..._document_freshness] min_fresh set, age limit: %d", age_limit);
    }
  }
   
   
   
   
  if (s->cache_control.revalidate_after >= 0) {
     
 

     
    age_limit = s->cache_control.revalidate_after;

    DebugTxn("http_match", "[..._document_freshness] revalidate_after set, age limit: %d", age_limit);
  }

  DebugTxn("http_match", "document_freshness --- current_age = %" PRId64, (int64_t)current_age);
  DebugTxn("http_match", "document_freshness --- age_limit   = %d", age_limit);
  DebugTxn("http_match", "document_freshness --- fresh_limit = %d", fresh_limit);
  DebugTxn("http_seq", "document_freshness --- current_age = %" PRId64, (int64_t)current_age);
  DebugTxn("http_seq", "document_freshness --- age_limit   = %d", age_limit);
  DebugTxn("http_seq", "document_freshness --- fresh_limit = %d", fresh_limit);
   
   
   

  if (do_revalidate || current_age > age_limit) {  
    DebugTxn("http_match", "[..._document_freshness] document needs revalidate/too old; "
            "returning FRESHNESS_STALE");
    return (FRESHNESS_STALE);
  } else if (current_age > fresh_limit) {   
    if (os_specifies_revalidate) {
      DebugTxn("http_match", "[..._document_freshness] document is stale and OS specifies revalidation; "
              "returning FRESHNESS_STALE");
      return (FRESHNESS_STALE);
    }
    DebugTxn("http_match", "[..._document_freshness] document is stale but no revalidation explicitly required; "
            "returning FRESHNESS_WARNING");
    return (FRESHNESS_WARNING);
  } else {
    DebugTxn("http_match", "[..._document_freshness] document is fresh; returning FRESHNESS_FRESH");
    return (FRESHNESS_FRESH);
  }
}