HttpTransact::issue_revalidate(State* s)
{
  HTTPHdr *c_resp = find_appropriate_cached_resp(s);
  SET_VIA_STRING(VIA_CACHE_RESULT, VIA_IN_CACHE_STALE);
  ink_assert(GET_VIA_STRING(VIA_DETAIL_CACHE_LOOKUP) != ' ');

  if (s->www_auth_content == CACHE_AUTH_FRESH) {
    s->hdr_info.server_request.method_set(HTTP_METHOD_HEAD, HTTP_LEN_HEAD);
    // The document is fresh in cache and we just want to see if the
    // the client has the right credentials
    // this cache action is just to get us into the hcoofsr function
    s->cache_info.action = CACHE_DO_UPDATE;
    DUMP_HEADER("http_hdrs", &s->hdr_info.server_request, s->state_machine_id, "Proxy's Request (Conditionalized)");
    return;
  }

  if (s->cache_info.write_lock_state == CACHE_WL_INIT) {
    // We do a cache lookup for DELETE, PUT and POST requests as well.
    // We must, however, delete the cached copy after forwarding the
    // request to the server. is_cache_response_returnable will ensure
    // that we forward the request. We now specify what the cache
    // action should be when the response is received.
    if (does_method_require_cache_copy_deletion(s->http_config_param, s->method)) {
      s->cache_info.action = CACHE_PREPARE_TO_DELETE;
      DebugTxn("http_seq", "[HttpTransact::issue_revalidate] cache action: DELETE");
    } else {
      s->cache_info.action = CACHE_PREPARE_TO_UPDATE;
      DebugTxn("http_seq", "[HttpTransact::issue_revalidate] cache action: UPDATE");
    }
  } else {
    // We've looped back around due to missing the write lock
    //  for the cache.  At this point we want to forget about the cache
    ink_assert(s->cache_info.write_lock_state == CACHE_WL_READ_RETRY);
    s->cache_info.action = CACHE_DO_NO_ACTION;
    return;
  }

  // if the document is cached, just send a conditional request to the server

  // So the request does not have preconditions. It can, however
  // be a simple GET request with a Pragma:no-cache. As on 8/28/98
  // we have fixed the whole Reload/Shift-Reload cached copy
  // corruption problem. This means that we can issue a conditional
  // request to the server only if the incoming request has a conditional
  // or the incoming request does NOT have a no-cache header.
  // In other words, if the incoming request is not conditional
  // but has a no-cache header we can not issue an IMS. check for
  // that case here.
  bool no_cache_in_request = false;

  if (s->hdr_info.client_request.is_pragma_no_cache_set() ||
      s->hdr_info.client_request.is_cache_control_set(HTTP_VALUE_NO_CACHE)) {
    DebugTxn("http_trans", "[issue_revalidate] no-cache header directive in request, folks");
    no_cache_in_request = true;
  }

  if ((!(s->hdr_info.client_request.presence(MIME_PRESENCE_IF_MODIFIED_SINCE))) &&
      (!(s->hdr_info.client_request.presence(MIME_PRESENCE_IF_NONE_MATCH))) &&
      (no_cache_in_request == true) &&
      (!s->txn_conf->cache_ims_on_client_no_cache) && (s->www_auth_content == CACHE_AUTH_NONE)) {
    DebugTxn("http_trans", "[issue_revalidate] Can not make this a conditional request. This is the force update of the cached copy case");
    // set cache action to update. response will be a 200 or error,
    // causing cached copy to be replaced (if 200).
    s->cache_info.action = CACHE_PREPARE_TO_UPDATE;
    return;
  }
  // do not conditionalize if the cached response is not a 200
  switch (c_resp->status_get()) {
  case HTTP_STATUS_OK:         // 200
    // don't conditionalize if we are configured to repeat the clients
    //   conditionals
    if (s->txn_conf->cache_when_to_revalidate == 4)
      break;
    // ok, request is either a conditional or does not have a no-cache.
    //   (or is method that we don't conditionalize but lookup the
    //    cache on like DELETE)
    if (c_resp->get_last_modified() > 0 &&
        (s->hdr_info.server_request.method_get_wksidx() == HTTP_WKSIDX_GET ||
         s->hdr_info.server_request.method_get_wksidx() == HTTP_WKSIDX_HEAD) && s->range_setup == RANGE_NONE) {
      // make this a conditional request
      int length;
      const char *str = c_resp->value_get(MIME_FIELD_LAST_MODIFIED, MIME_LEN_LAST_MODIFIED, &length);

      s->hdr_info.server_request.value_set(MIME_FIELD_IF_MODIFIED_SINCE, MIME_LEN_IF_MODIFIED_SINCE, str, length);
      if (!s->cop_test_page)
        DUMP_HEADER("http_hdrs", &s->hdr_info.server_request, s->state_machine_id, "Proxy's Request (Conditionalized)");
    }
    // if Etag exists, also add if-non-match header
    if (c_resp->presence(MIME_PRESENCE_ETAG) &&
        (s->hdr_info.server_request.method_get_wksidx() == HTTP_WKSIDX_GET ||
         s->hdr_info.server_request.method_get_wksidx() == HTTP_WKSIDX_HEAD)) {
      int length;
      const char *etag = c_resp->value_get(MIME_FIELD_ETAG, MIME_LEN_ETAG, &length);
      if ((length >= 2) && (etag[0] == 'W') && (etag[1] == '/')) {
        etag += 2;
        length -= 2;
      }
      s->hdr_info.server_request.value_set(MIME_FIELD_IF_NONE_MATCH, MIME_LEN_IF_NONE_MATCH, etag, length);
      if (!s->cop_test_page)
        DUMP_HEADER("http_hdrs", &s->hdr_info.server_request, s->state_machine_id, "Proxy's Request (Conditionalized)");
    }
    break;
  case HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION:      // 203
    /* fall through */
  case HTTP_STATUS_MULTIPLE_CHOICES:   // 300
    /* fall through */
  case HTTP_STATUS_MOVED_PERMANENTLY:  // 301
    /* fall through */
  case HTTP_STATUS_GONE:       // 410
    /* fall through */
  default:
    DebugTxn("http_trans", "[issue_revalidate] cached response is" "not a 200 response so no conditionalization.");
    s->cache_info.action = CACHE_PREPARE_TO_UPDATE;
    break;
  case HTTP_STATUS_PARTIAL_CONTENT:
    ink_assert(!"unexpected status code");
    break;
  }
}