HttpTransact::handle_response_from_server(State* s)
{
  DebugTxn("http_trans", "[handle_response_from_server] (hrfs)");
  HTTP_RELEASE_ASSERT(s->current.server == &s->server_info);
  int max_connect_retries = 0;

  // plugin call
  s->server_info.state = s->current.state;
  if (s->fp_tsremap_os_response) {
    s->fp_tsremap_os_response(s->remap_plugin_instance, reinterpret_cast<TSHttpTxn>(s->state_machine), s->current.state);
  }

  switch (s->current.state) {
  case CONNECTION_ALIVE:
    DebugTxn("http_trans", "[hrfs] connection alive");
    SET_VIA_STRING(VIA_DETAIL_SERVER_CONNECT, VIA_DETAIL_SERVER_SUCCESS);
    s->current.server->clear_connect_fail();
    handle_forward_server_connection_open(s);
    break;
  case CONGEST_CONTROL_CONGESTED_ON_F:
  case CONGEST_CONTROL_CONGESTED_ON_M:
    DebugTxn("http_trans", "[handle_response_from_server] Error. congestion control -- congested.");
    SET_VIA_STRING(VIA_DETAIL_SERVER_CONNECT, VIA_DETAIL_SERVER_FAILURE);
    s->current.server->set_connect_fail(EUSERS); // too many users
    handle_server_connection_not_open(s);
    break;
  case OPEN_RAW_ERROR:
    /* fall through */
  case CONNECTION_ERROR:
    /* fall through */
  case STATE_UNDEFINED:
    /* fall through */
  case INACTIVE_TIMEOUT:
    /* fall through */
  case PARSE_ERROR:
    /* fall through */
  case CONNECTION_CLOSED:
    /* fall through */
  case BAD_INCOMING_RESPONSE:
    // Set to generic I/O error if not already set specifically.
    if (!s->current.server->had_connect_fail())
      s->current.server->set_connect_fail(EIO);

    if (is_server_negative_cached(s)) {
      max_connect_retries = s->txn_conf->connect_attempts_max_retries_dead_server;
    } else {
      // server not yet negative cached - use default number of retries
      max_connect_retries = s->txn_conf->connect_attempts_max_retries;
    }
    if (s->pCongestionEntry != NULL)
      max_connect_retries = s->pCongestionEntry->connect_retries();

    if (is_request_retryable(s) && s->current.attempts < max_connect_retries) {
      // If this is a round robin DNS entry & we're tried configured
      //    number of times, we should try another node
      if (DNSLookupInfo::OS_ADDR_TRY_CLIENT == s->dns_info.os_addr_style) {
        // attempt was based on client supplied server address. Try again
        // using HostDB.
        // Allow DNS attempt
        s->dns_info.lookup_success = false;
        // See if we can get data from HostDB for this.
        s->dns_info.os_addr_style = DNSLookupInfo::OS_ADDR_TRY_HOSTDB;
        // Force host resolution to have the same family as the client.
        // Because this is a transparent connection, we can't switch address
        // families - that is locked in by the client source address.
        s->state_machine->ua_session->host_res_style = ats_host_res_match(&s->current.server->addr.sa);
        TRANSACT_RETURN(SM_ACTION_DNS_LOOKUP, OSDNSLookup);
      } else if ((s->dns_info.srv_lookup_success || s->server_info.dns_round_robin) &&
                 (s->txn_conf->connect_attempts_rr_retries > 0) &&
                 (s->current.attempts % s->txn_conf->connect_attempts_rr_retries == 0)) {
        delete_server_rr_entry(s, max_connect_retries);
        return;
      } else {
        retry_server_connection_not_open(s, s->current.state, max_connect_retries);
        DebugTxn("http_trans", "[handle_response_from_server] Error. Retrying...");
        s->next_action = how_to_open_connection(s);
        return;
      }
    } else {
      DebugTxn("http_trans", "[handle_response_from_server] Error. No more retries.");
      SET_VIA_STRING(VIA_DETAIL_SERVER_CONNECT, VIA_DETAIL_SERVER_FAILURE);
      handle_server_connection_not_open(s);
    }
    break;
  case ACTIVE_TIMEOUT:
    DebugTxn("http_trans", "[hrfs] connection not alive");
    SET_VIA_STRING(VIA_DETAIL_SERVER_CONNECT, VIA_DETAIL_SERVER_FAILURE);
    s->current.server->set_connect_fail(ETIMEDOUT);
    handle_server_connection_not_open(s);
    break;
  default:
    ink_assert(!("s->current.state is set to something unsupported"));
    break;
  }

  return;
}