Skip to content
transfer.c 75.5 KiB
Newer Older
        char *gotourl = strdup(data->change.url);
        res = Curl_follow(data, gotourl);
        if(res)
          free(gotourl);
      }
    }
  } while (urlchanged && res == CURLE_OK);

  return res;
}



Daniel Stenberg's avatar
Daniel Stenberg committed
/*
 * Curl_perform() is the internal high-level function that gets called by the
 * external curl_easy_perform() function. It inits, performs and cleans up a
 * single file transfer.
 */
CURLcode Curl_perform(struct SessionHandle *data)
{
  CURLcode res;
  CURLcode res2;
  struct connectdata *conn=NULL;
  char *newurl = NULL; /* possibly a new URL to follow to! */

  data->state.used_interface = Curl_if_easy;

  res = Curl_pretransfer(data);
  if(res)
    return res;

Daniel Stenberg's avatar
Daniel Stenberg committed
   * It is important that there is NO 'return' from this function at any other
   * place than falling down to the end of the function! This is because we
   * have cleanup stuff that must be done before we get back, and that is only
   * performed after this do-while loop.
    res = Curl_connect_host(data, &conn);   /* primary connection */

    if(res == CURLE_OK) {
      if (data->set.source_host) /* 3rd party transfer */
        res = Curl_pretransfersec(conn);
      else
        conn->sec_conn = NULL;
    }
    if(res == CURLE_OK) {
      res = Curl_do(&conn);
      /* for non 3rd party transfer only */
      if(res == CURLE_OK && !data->set.source_host) {
        res = Transfer(conn); /* now fetch that URL please */
          if((conn->keep.bytecount+conn->headerbytecount == 0) &&
            /* We got no data and we attempted to re-use a connection. This
               might happen if the connection was left alive when we were done
               using it before, but that was closed when we wanted to read
               from it again. Bad luck. Retry the same request on a fresh
               connect! */
            infof(data, "Connection died, retrying a fresh connect\n");
            newurl = strdup(conn->data->change.url);

            conn->bits.close = TRUE; /* close this connection */
            conn->bits.retry = TRUE; /* mark this as a connection we're about
                                        to retry. Marking it this way should
                                        prevent i.e HTTP transfers to return
                                        error just because nothing has been
                                        transfered! */
          }
          else
            /*
             * We must duplicate the new URL here as the connection data
             * may be free()ed in the Curl_done() function.
             */
            newurl = conn->newurl?strdup(conn->newurl):NULL;
        }
          /* The transfer phase returned error, we mark the connection to get
           * closed to prevent being re-used. This is becasue we can't
           * possibly know if the connection is in a good shape or not now. */
          conn->bits.close = TRUE;
          if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
            /* if we failed anywhere, we must clean up the secondary socket if
               it was used */
            conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
        /* Always run Curl_done(), even if some of the previous calls
           failed, but return the previous (original) error code */
      else
        /* Curl_do() failed, clean up left-overs in the done-call */
      /*
       * Important: 'conn' cannot be used here, since it may have been closed
       * in 'Curl_done' or other functions.
       */

      if((res == CURLE_OK) && newurl) {
        res = Curl_follow(data, newurl);
        if(CURLE_OK == res) {
          newurl = NULL;
          continue;
      }
    }
    break; /* it only reaches here when this shouldn't loop */

  } while(1); /* loop if Location: */

  /* run post-transfer uncondionally, but don't clobber the return code if
     we already have an error code recorder */
  res2 = Curl_posttransfer(data);
  if(!res && res2)
    res = res2;
Daniel Stenberg's avatar
Daniel Stenberg committed
/*
 * Curl_Transfer() is called to setup some basic properties for the upcoming
 * transfer.
 */
Curl_Transfer(struct connectdata *c_conn, /* connection data */
              int sockindex,       /* socket index to read from or -1 */
              curl_off_t size,     /* -1 if unknown at this point */
              bool getheader,      /* TRUE if header parsing is wanted */
              curl_off_t *bytecountp, /* return number of bytes read or NULL */
              int writesockindex,  /* socket index to write to, it may very
                                      well be the same we read from. -1
                                      disables */
              curl_off_t *writecountp /* return number of bytes written or
                                       NULL */
              )
{
  struct connectdata *conn = (struct connectdata *)c_conn;
  if(!conn)
    return CURLE_BAD_FUNCTION_ARGUMENT;

  curlassert((sockindex <= 1) && (sockindex >= -1));
  /* now copy all input parameters */
  conn->sockfd = sockindex==-1?
    CURL_SOCKET_BAD:conn->sock[sockindex];
  conn->bits.getheader = getheader;
  conn->bytecountp = bytecountp;
  conn->writesockfd = writesockindex==-1?
    CURL_SOCKET_BAD:conn->sock[writesockindex];
  conn->writebytecountp = writecountp;

/*
 * Curl_pretransfersec() prepares the secondary connection (used for 3rd party
 * FTP transfers).
 */
CURLcode Curl_pretransfersec(struct connectdata *conn)
{
  CURLcode status = CURLE_OK;
  struct SessionHandle *data = conn->data;
  struct connectdata *sec_conn = NULL;   /* secondary connection */

  /* update data with source host options */
  char *url = aprintf( "%s://%s/", conn->protostr, data->set.source_host);

  if(!url)
    return CURLE_OUT_OF_MEMORY;

  if(data->change.url_alloc)
    free(data->change.url);

  data->change.url_alloc = TRUE;
  data->change.url = url;
  data->set.ftpport = data->set.source_port;
  data->set.userpwd = data->set.source_userpwd;

  /* secondary connection */
  status = Curl_connect_host(data, &sec_conn);
  if(CURLE_OK == status) {
    sec_conn->data = data;
    conn->sec_conn = sec_conn;
  }