HttpTransact::handle_response_from_parent(State* s)
{
  DebugTxn("http_trans", "[handle_response_from_parent] (hrfp)");
  HTTP_RELEASE_ASSERT(s->current.server == &s->parent_info);

  s->parent_info.state = s->current.state;
  switch (s->current.state) {
  case CONNECTION_ALIVE:
    DebugTxn("http_trans", "[hrfp] connection alive");
    s->current.server->connect_result = 0;
    SET_VIA_STRING(VIA_DETAIL_PP_CONNECT, VIA_DETAIL_PP_SUCCESS);
    if (s->parent_result.retry) {
      s->parent_params->recordRetrySuccess(&s->parent_result);
    }
    handle_forward_server_connection_open(s);
    break;
  default:
    {
      LookingUp_t next_lookup = UNDEFINED_LOOKUP;
      DebugTxn("http_trans", "[hrfp] connection not alive");
      SET_VIA_STRING(VIA_DETAIL_PP_CONNECT, VIA_DETAIL_PP_FAILURE);

      ink_assert(s->hdr_info.server_request.valid());

      s->current.server->connect_result = ENOTCONN;

      char addrbuf[INET6_ADDRSTRLEN];
      DebugTxn("http_trans", "[%d] failed to connect to parent %s", s->current.attempts,
            ats_ip_ntop(&s->current.server->addr.sa, addrbuf, sizeof(addrbuf)));

      // If the request is not retryable, just give up!
      if (!is_request_retryable(s)) {
        s->parent_params->markParentDown(&s->parent_result);
        s->parent_result.r = PARENT_FAIL;
        handle_parent_died(s);
        return;
      }

      if (s->current.attempts < s->http_config_param->parent_connect_attempts) {
        s->current.attempts++;

        // Are we done with this particular parent?
        if ((s->current.attempts - 1) % s->http_config_param->per_parent_connect_attempts != 0) {
          // No we are not done with this parent so retry
          s->next_action = how_to_open_connection(s);
          DebugTxn("http_trans", "%s Retrying parent for attempt %d, max %" PRId64,
                "[handle_response_from_parent]", s->current.attempts, s->http_config_param->per_parent_connect_attempts);
          return;
        } else {
          DebugTxn("http_trans", "%s %d per parent attempts exhausted",
                "[handle_response_from_parent]", s->current.attempts);

          // Only mark the parent down if we failed to connect
          //  to the parent otherwise slow origin servers cause
          //  us to mark the parent down
          if (s->current.state == CONNECTION_ERROR) {
            s->parent_params->markParentDown(&s->parent_result);
          }
          // We are done so look for another parent if any
          next_lookup = find_server_and_update_current_info(s);
        }
      } else {
        // Done trying parents... fail over to origin server if that is
        //   appropriate
        DebugTxn("http_trans", "[handle_response_from_parent] Error. No more retries.");
        s->parent_params->markParentDown(&s->parent_result);
        s->parent_result.r = PARENT_FAIL;
        next_lookup = find_server_and_update_current_info(s);
      }

      // We have either tried to find a new parent or failed over to the
      //   origin server
      switch (next_lookup) {
      case PARENT_PROXY:
        ink_assert(s->current.request_to == PARENT_PROXY);
        TRANSACT_RETURN(SM_ACTION_DNS_LOOKUP, PPDNSLookup);
        break;
      case ORIGIN_SERVER:
        s->current.attempts = 0;
        s->next_action = how_to_open_connection(s);
        if (s->current.server == &s->server_info && s->next_hop_scheme == URL_WKSIDX_HTTP) {
          HttpTransactHeaders::remove_host_name_from_url(&s->hdr_info.server_request);
        }
        break;
      case HOST_NONE:
        handle_parent_died(s);
        break;
      default:
        // This handles:
        // UNDEFINED_LOOKUP, ICP_SUGGESTED_HOST,
        // INCOMING_ROUTER
        break;
      }

      break;
    }
  }
}