📄 transfer.c
字号:
conn->writesockfd, /* socket to send to */ conn->upload_fromhere, /* buffer pointer */ conn->upload_present, /* buffer size */ &bytes_written); /* actually send away */ if(result) return result; if(data->set.verbose) /* show the data before we change the pointer upload_fromhere */ Curl_debug(data, CURLINFO_DATA_OUT, conn->upload_fromhere, bytes_written); if(conn->upload_present != bytes_written) { /* we only wrote a part of the buffer (if anything), deal with it! */ /* store the amount of bytes left in the buffer to write */ conn->upload_present -= bytes_written; /* advance the pointer where to find the buffer when the next send is to happen */ conn->upload_fromhere += bytes_written; writedone = TRUE; /* we are done, stop the loop */ } else { /* we've uploaded that buffer now */ conn->upload_fromhere = k->uploadbuf; conn->upload_present = 0; /* no more bytes left */ if(k->upload_done) { /* switch off writing, we're done! */ k->keepon &= ~KEEP_WRITE; /* we're done writing */ FD_ZERO(&k->wkeepfd); writedone = TRUE; } } k->writebytecount += bytes_written; Curl_pgrsSetUploadCounter(data, (double)k->writebytecount); } while(!writedone); /* loop until we're done writing! */ } } while(0); /* just to break out from! */ k->now = Curl_tvnow(); if(didwhat) { /* Update read/write counters */ if(conn->bytecountp) *conn->bytecountp = k->bytecount; /* read count */ if(conn->writebytecountp) *conn->writebytecountp = k->writebytecount; /* write count */ } else { /* no read no write, this is a timeout? */ if (k->write_after_100_header) { /* This should allow some time for the header to arrive, but only a very short time as otherwise it'll be too much wasted times too often. */ /* Quoting RFC2616, section "8.2.3 Use of the 100 (Continue) Status": Therefore, when a client sends this header field to an origin server (possibly via a proxy) from which it has never seen a 100 (Continue) status, the client SHOULD NOT wait for an indefinite period before sending the request body. */ int ms = Curl_tvdiff(k->now, k->start100); if(ms > CURL_TIMEOUT_EXPECT_100) { /* we've waited long enough, continue anyway */ k->write_after_100_header = FALSE; FD_SET (conn->writesockfd, &k->writefd); /* write socket */ k->keepon |= KEEP_WRITE; k->wkeepfd = k->writefd; } } } if(Curl_pgrsUpdate(conn)) result = CURLE_ABORTED_BY_CALLBACK; else result = Curl_speedcheck (data, k->now); if (result) return result; if (data->set.timeout && ((Curl_tvdiff(k->now, k->start)/1000) >= data->set.timeout)) { failf (data, "Operation timed out with %d out of %d bytes received", k->bytecount, conn->size); return CURLE_OPERATION_TIMEOUTED; } if(!k->keepon) { /* * The transfer has been performed. Just make some general checks before * returning. */ if(!(data->set.no_body) && k->contentlength && (k->bytecount != k->contentlength) && !conn->newurl) { failf(data, "transfer closed with %d bytes remaining to read", k->contentlength-k->bytecount); return CURLE_PARTIAL_FILE; } else if(conn->bits.chunk && conn->proto.http->chunk.datasize) { failf(data, "transfer closed with at least %d bytes remaining", conn->proto.http->chunk.datasize); return CURLE_PARTIAL_FILE; } if(Curl_pgrsUpdate(conn)) return CURLE_ABORTED_BY_CALLBACK; } /* Now update the "done" boolean we return */ *done = !k->keepon; return CURLE_OK;}CURLcode Curl_readwrite_init(struct connectdata *conn){ struct SessionHandle *data = conn->data; struct Curl_transfer_keeper *k = &conn->keep; /* NB: the content encoding software depends on this initialization of Curl_transfer_keeper. 08/28/02 jhrg */ memset(k, 0, sizeof(struct Curl_transfer_keeper)); k->start = Curl_tvnow(); /* start time */ k->now = k->start; /* current time is now */ k->header = TRUE; /* assume header */ k->httpversion = -1; /* unknown at this point */ data = conn->data; /* there's the root struct */ k->buf = data->state.buffer; k->uploadbuf = data->state.uploadbuffer; k->maxfd = (conn->sockfd>conn->writesockfd? conn->sockfd:conn->writesockfd)+1; k->hbufp = data->state.headerbuff; k->ignorebody=FALSE; Curl_pgrsTime(data, TIMER_PRETRANSFER); Curl_speedinit(data); Curl_pgrsSetUploadCounter(data, 0); Curl_pgrsSetDownloadCounter(data, 0); if (!conn->bits.getheader) { k->header = FALSE; if(conn->size > 0) Curl_pgrsSetDownloadSize(data, conn->size); } /* we want header and/or body, if neither then don't do this! */ if(conn->bits.getheader || !data->set.no_body) { FD_ZERO (&k->readfd); /* clear it */ if(conn->sockfd != -1) { FD_SET (conn->sockfd, &k->readfd); /* read socket */ k->keepon |= KEEP_READ; } FD_ZERO (&k->writefd); /* clear it */ if(conn->writesockfd != -1) { /* HTTP 1.1 magic: Even if we require a 100-return code before uploading data, we might need to write data before that since the REQUEST may not have been finished sent off just yet. Thus, we must check if the request has been sent before we set the state info where we wait for the 100-return code */ if (data->set.expect100header && (conn->proto.http->sending == HTTPSEND_BODY)) { /* wait with write until we either got 100-continue or a timeout */ k->write_after_100_header = TRUE; k->start100 = k->start; } else { if(data->set.expect100header) /* when we've sent off the rest of the headers, we must await a 100-continue */ k->wait100_after_headers = TRUE; FD_SET (conn->writesockfd, &k->writefd); /* write socket */ k->keepon |= KEEP_WRITE; } } /* get these in backup variables to be able to restore them on each lap in the select() loop */ k->rkeepfd = k->readfd; k->wkeepfd = k->writefd; } return CURLE_OK;}void Curl_single_fdset(struct connectdata *conn, fd_set *read_fd_set, fd_set *write_fd_set, fd_set *exc_fd_set, int *max_fd){ *max_fd = -1; /* init */ if(conn->keep.keepon & KEEP_READ) { FD_SET(conn->sockfd, read_fd_set); *max_fd = conn->sockfd; conn->keep.readfdp = read_fd_set; /* store the address of the set */ } if(conn->keep.keepon & KEEP_WRITE) { FD_SET(conn->writesockfd, write_fd_set); if(conn->writesockfd > *max_fd) *max_fd = conn->writesockfd; conn->keep.writefdp = write_fd_set; /* store the address of the set */ } /* we don't use exceptions, only touch that one to prevent compiler warnings! */ *exc_fd_set = *exc_fd_set;}/* * Transfer() * * This function is what performs the actual transfer. It is capable of * doing both ways simultaneously. * The transfer must already have been setup by a call to Curl_Transfer(). * * Note that headers are created in a preallocated buffer of a default size. * That buffer can be enlarged on demand, but it is never shrinken again. * * Parts of this function was once written by the friendly Mark Butler * <butlerm@xmission.com>. */static CURLcodeTransfer(struct connectdata *conn){ struct SessionHandle *data = conn->data; CURLcode result; struct Curl_transfer_keeper *k = &conn->keep; bool done=FALSE; Curl_readwrite_init(conn); if((conn->sockfd == -1) && (conn->writesockfd == -1)) /* nothing to read, nothing to write, we're already OK! */ return CURLE_OK; /* we want header and/or body, if neither then don't do this! */ if(!conn->bits.getheader && data->set.no_body) return CURLE_OK; k->writefdp = &k->writefd; /* store the address of the set */ k->readfdp = &k->readfd; /* store the address of the set */ while (!done) { struct timeval interval; k->readfd = k->rkeepfd; /* set these every lap in the loop */ k->writefd = k->wkeepfd; interval.tv_sec = 1; interval.tv_usec = 0; switch (select (k->maxfd, k->readfdp, k->writefdp, NULL, &interval)) { case -1: /* select() error, stop reading */#ifdef EINTR /* The EINTR is not serious, and it seems you might get this more ofen when using the lib in a multi-threaded environment! */ if(errno == EINTR) ; else#endif done = TRUE; /* no more read or write */ continue; case 0: /* timeout */ result = Curl_readwrite(conn, &done); break; default: /* readable descriptors */ result = Curl_readwrite(conn, &done); break; } if(result) return result; /* "done" signals to us if the transfer(s) are ready */ } return CURLE_OK;}CURLcode Curl_pretransfer(struct SessionHandle *data){ CURLcode res; if(!data->change.url) /* we can't do anything wihout URL */ return CURLE_URL_MALFORMAT;#ifdef USE_SSLEAY /* Init the SSL session ID cache here. We do it here since we want to do it after the *_setopt() calls (that could change the size) but before any transfer. */ res = Curl_SSL_InitSessions(data, data->set.ssl.numsessions); if(res) return res;#else (void)res;#endif data->set.followlocation=0; /* reset the location-follow counter */ data->state.this_is_a_follow = FALSE; /* reset this */ data->state.errorbuf = FALSE; /* no error has occurred */ /* set preferred authentication, default to basic */ data->state.authstage = 0; /* initialize authentication later */ /* If there was a list of cookie files to read and we haven't done it before, do it now! */ if(data->change.cookielist) { struct curl_slist *list = data->change.cookielist; Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); while(list) { data->cookies = Curl_cookie_init(data, list->data, data->cookies, data->set.cookiesession); list = list->next; } Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); curl_slist_free_all(data->change.cookielist); /* clean up list */ data->change.cookielist = NULL; /* don't do this again! */ } /* Allow data->set.use_port to set which port to use. This needs to be * disabled for example when we follow Location: headers to URLs using * different ports! */ data->state.allow_port = TRUE;#if defined(HAVE_SIGNAL) && defined(SIGPIPE) /************************************************************* * Tell signal handler to ignore SIGPIPE *************************************************************/ if(!data->set.no_signal) data->state.prev_signal = signal(SIGPIPE, SIG_IGN);#endif Curl_initinfo(data); /* reset session-specific information "variables" */ Curl_pgrsStartNow(data); return CURLE_OK;}CURLcode Curl_posttransfer(struct SessionHandle *data){#if defined(HAVE_SIGNAL) && defined(SIGPIPE) /* restore the signal handler for SIGPIPE before we get back */ if(!data->set.no_signal) signal(SIGPIPE, data->state.prev_signal);#endif return CURLE_OK;}static int strlen_url(char *url)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -