Commit d2af77e6 authored by Daniel Stenberg's avatar Daniel Stenberg
Browse files

Download() was merged with Upload() and now they both form the new Transfer()

function that deals with both directions at the same time.
parent a96c6e96
Loading
Loading
Loading
Loading
+351 −268
Original line number Diff line number Diff line
@@ -80,27 +80,37 @@

#define MAX(x,y) ((x)>(y)?(x):(y))

/* --- download a stream from a socket --- */
/* --- download and upload a stream from/to a socket --- */

/* This newly edited version of Download() was brought to us by the friendly
   Mark Butler <butlerm@xmission.com>. Re-indented with the indent command. */
/* Parts of this function was brought to us by the friendly Mark Butler
   <butlerm@xmission.com>. */

UrgError 
Download (struct UrlData *data,
	  int sockfd,		/* socket to read from */
Transfer (struct UrlData *data,
          /* READ stuff */
	  int sockfd,		/* socket to read from or -1 */
	  int size,		/* -1 if unknown at this point */
	  bool getheader,	/* TRUE if header parsing is wanted */
	  long *bytecountp	/* return number of bytes read */
	  long *bytecountp,	/* return number of bytes read or NULL */
          
          /* WRITE stuff */
          int writesockfd,      /* socket to write to, it may very well be
                                   the same we read from. -1 disables */
          long *writebytecountp /* return number of bytes written or NULL */
          

)
{
  char *buf = data->buffer;
  size_t nread;
  int bytecount = 0;
  long contentlength=0;
  int bytecount = 0; /* number of bytes read */
  int writebytecount = 0; /* number of bytes written */
  long contentlength=0; /* size of incoming data */
  struct timeval start = tvnow();
  struct timeval now = start;
  bool header = TRUE;
  int headerline = 0;		/* counts header lines to better track the first one */
  bool header = TRUE;		/* incoming data has HTTP header */
  int headerline = 0;		/* counts header lines to better track the
                                   first one */

  char *hbufp;			/* points at *end* of header line */
  int hbuflen = 0;
@@ -112,9 +122,6 @@ Download (struct UrlData *data,
  int offset = 0;		/* possible resume offset read from the
                                   Content-Range: header */
  int code = 0;			/* error code from the 'HTTP/1.? XXX' line */
#ifdef USE_ZLIB
  gzFile gzfile=NULL;
#endif

  /* for the low speed checks: */
  UrgError urg;
@@ -123,6 +130,9 @@ Download (struct UrlData *data,

  char newurl[URL_MAX_LENGTH];		/* buffer for Location: URL */

  /* the highest fd we use + 1 */
  int maxfd = (sockfd>writesockfd?sockfd:writesockfd)+1;

  hbufp = data->headerbuff;

  myalarm (0);			/* switch off the alarm-style timeout */
@@ -136,7 +146,9 @@ Download (struct UrlData *data,
  }
  {
    fd_set readfd;
    fd_set keepfd;
    fd_set writefd;
    fd_set rkeepfd;
    fd_set wkeepfd;
    struct timeval interval;
    bool keepon = TRUE;

@@ -148,35 +160,42 @@ Download (struct UrlData *data,
     */

    FD_ZERO (&readfd);		/* clear it */
    FD_SET (sockfd, &readfd);
    if(sockfd != -1) {
      FD_SET (sockfd, &readfd); /* read socket */
    }

    FD_ZERO (&writefd);		/* clear it */
    if(writesockfd != -1) {
      FD_SET (writesockfd, &writefd); /* write socket */
    }

    /* get these in backup variables to be able to restore them on each lap in
       the select() loop */
    rkeepfd = readfd;
    wkeepfd = writefd;

    keepfd = readfd;
#ifdef USE_ZLIB
    gzfile = gzdopen(sockfd, "rb");
#endif
    while (keepon) {
      readfd = keepfd;		/* set this every lap in the loop */
      interval.tv_sec = 2;
      readfd = rkeepfd;		/* set those every lap in the loop */
      writefd = wkeepfd;
      interval.tv_sec = 1;
      interval.tv_usec = 0;

      switch (select (sockfd + 1, &readfd, NULL, NULL, &interval)) {
      case -1:			/* error, stop reading */
      switch (select (maxfd, &readfd, &writefd, NULL, &interval)) {
      case -1:			/* select() error, stop reading */
	keepon = FALSE;
	continue;
      case 0:			/* timeout */
	break;
      default:			/* read! */
      default:
        if((sockfd>-1) && FD_ISSET(sockfd, &readfd)) {
          /* read! */
#ifdef USE_SSLEAY
          if (data->use_ssl) {
            nread = SSL_read (data->ssl, buf, BUFSIZE - 1);
          }
          else {
#endif
#ifdef USE_ZLIB
          nread = gzread(gzfile, buf, BUFSIZE -1 );
#else
            nread = sread (sockfd, buf, BUFSIZE - 1);
#endif
#ifdef USE_SSLEAY
          }
#endif /* USE_SSLEAY */
@@ -275,8 +294,10 @@ Download (struct UrlData *data,
                ProgressInit (data, size);	/* init progress meter */
                header = FALSE;	/* no more header to parse! */

	      /* now, only output this if the header AND body are requested: */
	      if ((data->conf & (CONF_HEADER | CONF_NOBODY)) == CONF_HEADER) {
                /* now, only output this if the header AND body are requested:
                 */
                if ((data->conf & (CONF_HEADER | CONF_NOBODY)) ==
                    CONF_HEADER) {
                  if((p - data->headerbuff) !=
                     data->fwrite (data->headerbuff, 1,
                                   p - data->headerbuff, data->out)) {
@@ -303,7 +324,8 @@ Download (struct UrlData *data,
                if (sscanf (p, " HTTP/1.%*c %3d", &code)) {
                  /* 404 -> URL not found! */
                  if (
                    ( ((data->conf & CONF_FOLLOWLOCATION) && (code >= 400)) ||
                      ( ((data->conf & CONF_FOLLOWLOCATION) && (code >= 400))
                        ||
                        !(data->conf & CONF_FOLLOWLOCATION) && (code >= 300))
                      && (data->conf & CONF_FAILONERROR)) {
                    /* If we have been told to fail hard on HTTP-errors,
@@ -333,7 +355,8 @@ Download (struct UrlData *data,
                      strnequal("Set-Cookie: ", p, 11)) {
                cookie_add(data->cookies, TRUE, &p[12]);
              }
            else if(strnequal("Last-Modified:", p, strlen("Last-Modified:")) &&
              else if(strnequal("Last-Modified:", p,
                                strlen("Last-Modified:")) &&
                      data->timecondition) {
                time_t secs=time(NULL);
                timeofdoc = get_date(p+strlen("Last-Modified:"), &secs);
@@ -392,8 +415,8 @@ Download (struct UrlData *data,
              if(data->conf&CONF_HTTP) {
                /* HTTP-only checks */
                if (data->resume_from && !content_range ) {
                /* we wanted to resume a download, although the server doesn't
                   seem to support this */
                  /* we wanted to resume a download, although the server
                     doesn't seem to support this */
                  failf (data, "HTTP server doesn't seem to support byte ranges. Cannot resume.");
                  return URG_HTTP_RANGE_ERROR;
                }
@@ -404,20 +427,23 @@ Download (struct UrlData *data,
                }
                else if(data->timecondition && !data->range) {
                  /* A time condition has been set AND no ranges have been
                   requested. This seems to be what chapter 13.3.4 of RFC 2616
                   defines to be the correct action for a HTTP/1.1 client */
                     requested. This seems to be what chapter 13.3.4 of
                     RFC 2616 defines to be the correct action for a
                     HTTP/1.1 client */
                  if((timeofdoc > 0) && (data->timevalue > 0)) {
                    switch(data->timecondition) {
                    case TIMECOND_IFMODSINCE:
                    default:
                      if(timeofdoc < data->timevalue) {
                      infof(data, "The requested document is not new enough");
                        infof(data,
                              "The requested document is not new enough");
                        return URG_OK;
                      }
                      break;
                    case TIMECOND_IFUNMODSINCE:
                      if(timeofdoc > data->timevalue) {
                      infof(data, "The requested document is not old enough");
                        infof(data,
                              "The requested document is not old enough");
                        return URG_OK;
                      }
                      break;
@@ -443,9 +469,64 @@ Download (struct UrlData *data,
              return URG_WRITE_ERROR;
            }

          } /* if (! header and data to read ) */
        } /* if( read from socket ) */

        if((writesockfd>-1) && FD_ISSET(writesockfd, &writefd)) {
          /* write */

          char scratch[BUFSIZE * 2];
          int i, si;
          int bytes_written;

          if(data->crlf)
            buf = data->buffer; /* put it back on the buffer */

          nread = data->fread(buf, 1, BUFSIZE, data->in);
          writebytecount += nread;

          if (nread<=0) {
            /* done */
            keepon = FALSE; 
            break;
          }

          /* convert LF to CRLF if so asked */
          if (data->crlf) {
            for(i = 0, si = 0; i < (int)nread; i++, si++) {
              if (buf[i] == 0x0a) {
                scratch[si++] = 0x0d;
                scratch[si] = 0x0a;
              }
              else {
                scratch[si] = buf[i];
              }
            }
            nread = si;
            buf = scratch; /* point to the new buffer */
          }

          /* write to socket */
#ifdef USE_SSLEAY
          if (data->use_ssl) {
            bytes_written = SSL_write(data->ssl, buf, nread);
          }
          else {
#endif
            bytes_written = swrite(writesockfd, buf, nread);
#ifdef USE_SSLEAY
          }
#endif /* USE_SSLEAY */
          if(nread != bytes_written) {
            failf(data, "Failed uploading data");
            return URG_WRITE_ERROR;
          }

        }

        break;
      }

      now = tvnow();
      if (!header) {
	ProgressShow (data, bytecount, start, now, FALSE);
@@ -467,17 +548,19 @@ Download (struct UrlData *data,
#endif
    }
  }
  if(contentlength && (bytecount != contentlength)) {
    failf(data, "transfer closed with %d bytes remaining", contentlength-bytecount);
  if(!(data->conf&CONF_NOBODY) && contentlength &&
     (bytecount != contentlength)) {
    failf(data, "transfer closed with %d bytes remaining to read",
          contentlength-bytecount);
    return URG_PARTIAL_FILE;
  }
  ProgressShow (data, bytecount, start, now, TRUE);

  *bytecountp = bytecount;
  if(bytecountp)
    *bytecountp = bytecount; /* read count */
  if(writebytecountp)
    *writebytecountp = writebytecount; /* write count */

#ifdef USE_ZLIB
  gzclose(gzfile);
#endif
  return URG_OK;
}

+6 −3
Original line number Diff line number Diff line
@@ -40,11 +40,14 @@
 * ------------------------------------------------------------
 ****************************************************************************/
UrgError 
Download (struct UrlData *data,
	  int sockfd,		/* socket to read from */
Transfer (struct UrlData *data,
	  int sockfd,		/* socket to read from or -1 */
	  int size,		/* -1 if unknown at this point */
	  bool getheader,	/* TRUE if header parsing is wanted */
	  long *bytecountp	/* return number of bytes read */
	  long *bytecountp,	/* return number of bytes read */
          int writesockfd,      /* socket to write to, it may very well be
                                   the same we read from. -1 disables */
          long *writebytecountp /* return number of bytes written */
);

#endif