aboutsummaryrefslogtreecommitdiffstats
path: root/lib/transfer.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/transfer.c')
-rw-r--r--lib/transfer.c169
1 files changed, 107 insertions, 62 deletions
diff --git a/lib/transfer.c b/lib/transfer.c
index 2d50405..78bd7f1 100644
--- a/lib/transfer.c
+++ b/lib/transfer.c
@@ -103,6 +103,7 @@
#include "multiif.h"
#include "easyif.h" /* for Curl_convert_to_network prototype */
#include "rtsp.h"
+#include "connect.h"
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
@@ -194,7 +195,8 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp)
/* \n will become \r\n later on */
endofline_native = "\n";
endofline_network = "\x0a";
- } else {
+ }
+ else {
endofline_native = "\r\n";
endofline_network = "\x0d\x0a";
}
@@ -219,21 +221,20 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp)
if(data->set.prefer_ascii) {
/* translate the protocol and data */
length = nread;
- } else {
+ }
+ else {
/* just translate the protocol portion */
length = strlen(hexbuffer);
}
res = Curl_convert_to_network(data, data->req.upload_fromhere, length);
/* Curl_convert_to_network calls failf if unsuccessful */
- if(res != CURLE_OK) {
+ if(res)
return(res);
- }
#endif /* CURL_DOES_CONVERSIONS */
- if((nread - hexlen) == 0) {
+ if((nread - hexlen) == 0)
/* mark this as done once this chunk is transfered */
data->req.upload_done = TRUE;
- }
nread+=(int)strlen(endofline_native); /* for the added end of line */
}
@@ -340,11 +341,11 @@ static void read_rewind(struct connectdata *conn,
show = CURLMIN(conn->buf_len - conn->read_pos, sizeof(buf)-1);
if(conn->master_buffer) {
- memcpy(buf, conn->master_buffer + conn->read_pos, show);
- buf[show] = '\0';
+ memcpy(buf, conn->master_buffer + conn->read_pos, show);
+ buf[show] = '\0';
}
else {
- buf[0] = '\0';
+ buf[0] = '\0';
}
DEBUGF(infof(conn->data,
@@ -376,12 +377,11 @@ static CURLcode readwrite_data(struct SessionHandle *data,
*done = FALSE;
/* This is where we loop until we have read everything there is to
- read or we get a EWOULDBLOCK */
+ read or we get a CURLE_AGAIN */
do {
size_t buffersize = data->set.buffer_size?
data->set.buffer_size : BUFSIZE;
size_t bytestoread = buffersize;
- int readrc;
if(k->size != -1 && !k->header) {
/* make sure we don't read "too much" if we can help it since we
@@ -394,15 +394,12 @@ static CURLcode readwrite_data(struct SessionHandle *data,
if(bytestoread) {
/* receive data from the network! */
- readrc = Curl_read(conn, conn->sockfd, k->buf, bytestoread, &nread);
+ result = Curl_read(conn, conn->sockfd, k->buf, bytestoread, &nread);
- /* subzero, this would've blocked */
- if(0 > readrc)
+ /* read would've blocked */
+ if(CURLE_AGAIN == result)
break; /* get out of loop */
- /* get the CURLcode from the int */
- result = (CURLcode)readrc;
-
if(result>0)
return result;
}
@@ -598,9 +595,12 @@ static CURLcode readwrite_data(struct SessionHandle *data,
dataleft = conn->chunk.dataleft;
if(dataleft != 0) {
- infof(conn->data, "Leftovers after chunking. "
- " Rewinding %zu bytes\n",dataleft);
- read_rewind(conn, dataleft);
+ infof(conn->data, "Leftovers after chunking: %zu bytes", dataleft);
+ if(conn->data->multi && Curl_multi_canPipeline(conn->data->multi)) {
+ /* only attempt the rewind if we truly are pipelining */
+ infof(conn->data, "Rewinding %zu bytes\n",dataleft);
+ read_rewind(conn, dataleft);
+ }
}
}
/* If it returned OK, we just keep going */
@@ -623,22 +623,22 @@ static CURLcode readwrite_data(struct SessionHandle *data,
/* The 'excess' amount below can't be more than BUFSIZE which
always will fit in a size_t */
infof(data,
- "Rewinding stream by : %zu"
- " bytes on url %s (size = %" FORMAT_OFF_T
- ", maxdownload = %" FORMAT_OFF_T
- ", bytecount = %" FORMAT_OFF_T ", nread = %zd)\n",
- excess, data->state.path,
- k->size, k->maxdownload, k->bytecount, nread);
+ "Rewinding stream by : %zu"
+ " bytes on url %s (size = %" FORMAT_OFF_T
+ ", maxdownload = %" FORMAT_OFF_T
+ ", bytecount = %" FORMAT_OFF_T ", nread = %zd)\n",
+ excess, data->state.path,
+ k->size, k->maxdownload, k->bytecount, nread);
read_rewind(conn, excess);
}
else {
infof(data,
- "Excess found in a non pipelined read:"
- " excess = %zu"
- ", size = %" FORMAT_OFF_T
- ", maxdownload = %" FORMAT_OFF_T
- ", bytecount = %" FORMAT_OFF_T "\n",
- excess, k->size, k->maxdownload, k->bytecount);
+ "Excess found in a non pipelined read:"
+ " excess = %zu"
+ ", size = %" FORMAT_OFF_T
+ ", maxdownload = %" FORMAT_OFF_T
+ ", bytecount = %" FORMAT_OFF_T "\n",
+ excess, k->size, k->maxdownload, k->bytecount);
}
}
@@ -738,7 +738,7 @@ static CURLcode readwrite_data(struct SessionHandle *data,
/* Parse the excess data */
k->str += nread;
- nread = excess;
+ nread = (ssize_t)excess;
result = Curl_rtsp_rtp_readwrite(data, conn, &nread, &readmore);
if(result)
@@ -815,6 +815,9 @@ static CURLcode readwrite_upload(struct SessionHandle *data,
k->keepon &= ~KEEP_SEND; /* disable writing */
k->start100 = Curl_tvnow(); /* timeout count starts now */
*didwhat &= ~KEEP_SEND; /* we didn't write anything actually */
+
+ /* set a timeout for the multi interface */
+ Curl_expire(data, CURL_TIMEOUT_EXPECT_100);
break;
}
@@ -994,7 +997,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
status is not known. */
select_res = Curl_socket_ready(fd_read, fd_write, 0);
- if(select_res == CURL_CSELECT_ERR) {
+ if(select_res & CURL_CSELECT_ERR) {
failf(data, "select/poll returned error");
return CURLE_SEND_ERROR;
}
@@ -1061,16 +1064,17 @@ CURLcode Curl_readwrite(struct connectdata *conn,
return result;
if(k->keepon) {
- if(data->set.timeout &&
- (Curl_tvdiff(k->now, k->start) >= data->set.timeout)) {
+ if(0 > Curl_timeleft(conn, &k->now, FALSE)) {
if(k->size != -1) {
failf(data, "Operation timed out after %ld milliseconds with %"
FORMAT_OFF_T " out of %" FORMAT_OFF_T " bytes received",
- Curl_tvdiff(k->now, k->start), k->bytecount, k->size);
- } else {
+ Curl_tvdiff(k->now, data->progress.t_startsingle), k->bytecount,
+ k->size);
+ }
+ else {
failf(data, "Operation timed out after %ld milliseconds with %"
FORMAT_OFF_T " bytes received",
- Curl_tvdiff(k->now, k->start), k->bytecount);
+ Curl_tvdiff(k->now, data->progress.t_startsingle), k->bytecount);
}
return CURLE_OPERATION_TIMEDOUT;
}
@@ -1225,7 +1229,7 @@ long Curl_sleep_time(curl_off_t rate_bps, curl_off_t cur_rate_bps,
*/
if(rv > 0x7fffffff)
rv = 0x7fffffff;
-
+
return (long)rv;
}
@@ -1343,12 +1347,10 @@ Transfer(struct connectdata *conn)
to work with, skip the timeout */
timeout_ms = 0;
else {
- if(data->set.timeout) {
- totmp = (int)(data->set.timeout - Curl_tvdiff(k->now, k->start));
- if(totmp < 0)
- return CURLE_OPERATION_TIMEDOUT;
- }
- else
+ totmp = Curl_timeleft(conn, &k->now, FALSE);
+ if(totmp < 0)
+ return CURLE_OPERATION_TIMEDOUT;
+ else if(!totmp)
totmp = 1000;
if (totmp < timeout_ms)
@@ -1433,6 +1435,12 @@ CURLcode Curl_pretransfer(struct SessionHandle *data)
Curl_initinfo(data); /* reset session-specific information "variables" */
Curl_pgrsStartNow(data);
+ if(data->set.timeout)
+ Curl_expire(data, data->set.timeout);
+
+ if(data->set.connecttimeout)
+ Curl_expire(data, data->set.connecttimeout);
+
return CURLE_OK;
}
@@ -2009,12 +2017,7 @@ CURLcode Curl_retry_request(struct connectdata *conn,
return CURLE_OK;
}
-/*
- * 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)
+static CURLcode Curl_do_perform(struct SessionHandle *data)
{
CURLcode res;
CURLcode res2;
@@ -2049,6 +2052,15 @@ CURLcode Curl_perform(struct SessionHandle *data)
res = Curl_do(&conn, &do_done);
if(res == CURLE_OK) {
+ if(conn->data->set.wildcardmatch) {
+ if(conn->data->wildcard.state == CURLWC_DONE ||
+ conn->data->wildcard.state == CURLWC_SKIP) {
+ /* keep connection open for application to use the socket */
+ conn->bits.close = FALSE;
+ res = Curl_done(&conn, CURLE_OK, FALSE);
+ break;
+ }
+ }
res = Transfer(conn); /* now fetch that URL please */
if((res == CURLE_OK) || (res == CURLE_RECV_ERROR)) {
bool retry = FALSE;
@@ -2056,13 +2068,12 @@ CURLcode Curl_perform(struct SessionHandle *data)
if(rc)
res = rc;
else
- retry = (bool)(newurl?TRUE:FALSE);
+ retry = (newurl?TRUE:FALSE);
if(retry) {
+ /* we know (newurl != NULL) at this point */
res = CURLE_OK;
follow = FOLLOW_RETRY;
- if (!newurl)
- res = CURLE_OUT_OF_MEMORY;
}
else if (res == CURLE_OK) {
/*
@@ -2113,9 +2124,9 @@ CURLcode Curl_perform(struct SessionHandle *data)
/* Curl_do() failed, clean up left-overs in the done-call, but note
that at some cases the conn pointer is NULL when Curl_do() failed
and the connection cache is very small so only call Curl_done() if
- conn is still "alive".
- */
- res2 = Curl_done(&conn, res, FALSE);
+ conn is still "alive". */
+ /* ignore return code since we already have an error to return */
+ (void)Curl_done(&conn, res, FALSE);
/*
* Important: 'conn' cannot be used here, since it may have been closed
@@ -2166,10 +2177,43 @@ CURLcode Curl_perform(struct SessionHandle *data)
}
/*
+ * 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;
+ if(!data->set.wildcardmatch)
+ return Curl_do_perform(data);
+
+ /* init main wildcard structures */
+ res = Curl_wildcard_init(&data->wildcard);
+ if(res)
+ return res;
+
+ res = Curl_do_perform(data);
+ if(res) {
+ Curl_wildcard_dtor(&data->wildcard);
+ return res;
+ }
+
+ /* wildcard loop */
+ while(!res && data->wildcard.state != CURLWC_DONE)
+ res = Curl_do_perform(data);
+
+ Curl_wildcard_dtor(&data->wildcard);
+
+ /* wildcard download finished or failed */
+ data->wildcard.state = CURLWC_INIT;
+ return res;
+}
+
+/*
* Curl_setup_transfer() is called to setup some basic properties for the
* upcoming transfer.
*/
-CURLcode
+void
Curl_setup_transfer(
struct connectdata *conn, /* connection data */
int sockindex, /* socket index to read from or -1 */
@@ -2214,9 +2258,8 @@ Curl_setup_transfer(
/* we want header and/or body, if neither then don't do this! */
if(k->getheader || !data->set.opt_no_body) {
- if(conn->sockfd != CURL_SOCKET_BAD) {
+ if(conn->sockfd != CURL_SOCKET_BAD)
k->keepon |= KEEP_RECV;
- }
if(conn->writesockfd != CURL_SOCKET_BAD) {
/* HTTP 1.1 magic:
@@ -2233,6 +2276,9 @@ Curl_setup_transfer(
/* wait with write until we either got 100-continue or a timeout */
k->exp100 = EXP100_AWAITING_CONTINUE;
k->start100 = k->start;
+
+ /* set a timeout for the multi interface */
+ Curl_expire(data, CURL_TIMEOUT_EXPECT_100);
}
else {
if(data->state.expect100header)
@@ -2246,5 +2292,4 @@ Curl_setup_transfer(
} /* if(conn->writesockfd != CURL_SOCKET_BAD) */
} /* if(k->getheader || !data->set.opt_no_body) */
- return CURLE_OK;
}