Skip to content
url.c 125 KiB
Newer Older
{
  CURLcode result;
  struct SessionHandle *data = conn->data;
  if(conn->bits.done)
    return CURLE_OK; /* Curl_done() has already been called */

  conn->bits.done = TRUE; /* called just now! */

  if(Curl_removeHandleFromPipeline(data, conn->recv_pipe) &&
     conn->readchannel_inuse)
  if(Curl_removeHandleFromPipeline(data, conn->send_pipe) &&
     conn->writechannel_inuse)
  /* cleanups done even if the connection is re-used */
  if(data->reqdata.rangestringalloc) {
    free(data->reqdata.range);
    data->reqdata.rangestringalloc = FALSE;
  }

  /* Cleanup possible redirect junk */
  if(data->reqdata.newurl) {
    free(data->reqdata.newurl);
    data->reqdata.newurl = NULL;
  if(conn->dns_entry) {
    Curl_resolv_unlock(data, conn->dns_entry); /* done with this */
    conn->dns_entry = NULL;
  }

  /* this calls the protocol-specific function pointer previously set */
  if(conn->curl_done)
    result = conn->curl_done(conn, status);
  else
    result = CURLE_OK;

  Curl_pgrsDone(conn); /* done with the operation */
  /* for ares-using, make sure all possible outstanding requests are properly
     cancelled before we proceed */
  ares_cancel(data->state.areschannel);

  ConnectionDone(conn); /* the connection is no longer in use */

  /* if data->set.reuse_forbid is TRUE, it means the libcurl client has
     forced us to close this no matter what we think.
     if conn->bits.close is TRUE, it means that the connection should be
     closed in spite of all our efforts to be nice, due to protocol
     restrictions in our or the server's end */
  if(data->set.reuse_forbid || conn->bits.close) {
    CURLcode res2;
    res2 = Curl_disconnect(conn); /* close the connection */

    *connp = NULL; /* to make the caller of this function better detect that
                      this was actually killed here */

    /* If we had an error already, make sure we return that one. But
       if we got a new error, return that. */
    if(!result && res2)
      result = res2;
  }
  else {
    /* remember the most recently used connection */
    data->state.lastconnect = conn->connectindex;

    infof(data, "Connection #%ld to host %s left intact\n",
          conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname);
CURLcode Curl_do(struct connectdata **connp, bool *done)
  CURLcode result=CURLE_OK;
  struct connectdata *conn = *connp;
  struct SessionHandle *data = conn->data;
  conn->bits.done = FALSE; /* Curl_done() is not called yet */
  conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to use */
    /* generic protocol-specific function pointer set in curl_connect() */
    /* This was formerly done in transfer.c, but we better do it here */
    if((CURLE_SEND_ERROR == result) && conn->bits.reuse) {
      /* This was a re-use of a connection and we got a write error in the
       * DO-phase. Then we DISCONNECT this connection and have another attempt
       * to CONNECT and then DO again! The retry cannot possibly find another
       * connection to re-use, since we only keep one possible connection for
       * each.  */

      infof(data, "Re-used connection seems dead, get a new one\n");

      conn->bits.close = TRUE; /* enforce close of this connection */
      result = Curl_done(&conn, result); /* we are so done with this */
      /* conn may no longer be a good pointer */
      /*
       * According to bug report #1330310. We need to check for
       * CURLE_SEND_ERROR here as well. I figure this could happen when the
       * request failed on a FTP connection and thus Curl_done() itself tried
       * to use the connection (again). Slight Lack of feedback in the report,
       * but I don't think this extra check can do much harm.
       */
      if((CURLE_OK == result) || (CURLE_SEND_ERROR == result)) {
        /* Now, redo the connect and get a new connection */
        result = Curl_connect(data, connp, &async, &protocol_done);
        if(CURLE_OK == result) {
          /* We have connected or sent away a name resolve query fine */

          conn = *connp; /* setup conn to again point to something nice */
          if(async) {
            /* Now, if async is TRUE here, we need to wait for the name
               to resolve */
            result = Curl_wait_for_resolv(conn, NULL);
            if(result)
              return result;
            /* Resolved, continue with the connection */
            result = Curl_async_resolved(conn, &protocol_done);
          /* ... finally back to actually retry the DO phase */
CURLcode Curl_do_more(struct connectdata *conn)
{
  CURLcode result=CURLE_OK;

  if(conn->curl_do_more)
    result = conn->curl_do_more(conn);

  return result;
}