summaryrefslogtreecommitdiff
path: root/Utilities/cmcurl/lib/transfer.c
diff options
context:
space:
mode:
Diffstat (limited to 'Utilities/cmcurl/lib/transfer.c')
-rw-r--r--Utilities/cmcurl/lib/transfer.c198
1 files changed, 60 insertions, 138 deletions
diff --git a/Utilities/cmcurl/lib/transfer.c b/Utilities/cmcurl/lib/transfer.c
index 441da73429..ba0410fc51 100644
--- a/Utilities/cmcurl/lib/transfer.c
+++ b/Utilities/cmcurl/lib/transfer.c
@@ -64,6 +64,7 @@
#include "content_encoding.h"
#include "hostip.h"
+#include "cfilters.h"
#include "transfer.h"
#include "sendf.h"
#include "speedcheck.h"
@@ -362,89 +363,7 @@ CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes,
return CURLE_OK;
}
-
-/*
- * Curl_readrewind() rewinds the read stream. This is typically used for HTTP
- * POST/PUT with multi-pass authentication when a sending was denied and a
- * resend is necessary.
- */
-CURLcode Curl_readrewind(struct Curl_easy *data)
-{
- struct connectdata *conn = data->conn;
- curl_mimepart *mimepart = &data->set.mimepost;
-
- conn->bits.rewindaftersend = FALSE; /* we rewind now */
-
- /* explicitly switch off sending data on this connection now since we are
- about to restart a new transfer and thus we want to avoid inadvertently
- sending more data on the existing connection until the next transfer
- starts */
- data->req.keepon &= ~KEEP_SEND;
-
- /* We have sent away data. If not using CURLOPT_POSTFIELDS or
- CURLOPT_HTTPPOST, call app to rewind
- */
- if(conn->handler->protocol & PROTO_FAMILY_HTTP) {
- struct HTTP *http = data->req.p.http;
-
- if(http->sendit)
- mimepart = http->sendit;
- }
- if(data->set.postfields)
- ; /* do nothing */
- else if(data->state.httpreq == HTTPREQ_POST_MIME ||
- data->state.httpreq == HTTPREQ_POST_FORM) {
- CURLcode result = Curl_mime_rewind(mimepart);
- if(result) {
- failf(data, "Cannot rewind mime/post data");
- return result;
- }
- }
- else {
- if(data->set.seek_func) {
- int err;
-
- Curl_set_in_callback(data, true);
- err = (data->set.seek_func)(data->set.seek_client, 0, SEEK_SET);
- Curl_set_in_callback(data, false);
- if(err) {
- failf(data, "seek callback returned error %d", (int)err);
- return CURLE_SEND_FAIL_REWIND;
- }
- }
- else if(data->set.ioctl_func) {
- curlioerr err;
-
- Curl_set_in_callback(data, true);
- err = (data->set.ioctl_func)(data, CURLIOCMD_RESTARTREAD,
- data->set.ioctl_client);
- Curl_set_in_callback(data, false);
- infof(data, "the ioctl callback returned %d", (int)err);
-
- if(err) {
- failf(data, "ioctl callback returned error %d", (int)err);
- return CURLE_SEND_FAIL_REWIND;
- }
- }
- else {
- /* If no CURLOPT_READFUNCTION is used, we know that we operate on a
- given FILE * stream and we can actually attempt to rewind that
- ourselves with fseek() */
- if(data->state.fread_func == (curl_read_callback)fread) {
- if(-1 != fseek(data->state.in, 0, SEEK_SET))
- /* successful rewind */
- return CURLE_OK;
- }
-
- /* no callback set or failure above, makes us fail at once */
- failf(data, "necessary data rewind wasn't possible");
- return CURLE_SEND_FAIL_REWIND;
- }
- }
- return CURLE_OK;
-}
-
-static int data_pending(const struct Curl_easy *data)
+static int data_pending(struct Curl_easy *data)
{
struct connectdata *conn = data->conn;
@@ -454,7 +373,7 @@ static int data_pending(const struct Curl_easy *data)
#endif
if(conn->handler->protocol&PROTO_FAMILY_FTP)
- return Curl_ssl_data_pending(conn, SECONDARYSOCKET);
+ return Curl_conn_data_pending(data, SECONDARYSOCKET);
/* in the case of libssh2, we can never be really sure that we have emptied
its internal buffers so we MUST always try until we get EAGAIN back */
@@ -469,7 +388,7 @@ static int data_pending(const struct Curl_easy *data)
a workaround, we return nonzero here to call http2_recv. */
((conn->handler->protocol&PROTO_FAMILY_HTTP) && conn->httpversion >= 20) ||
#endif
- Curl_ssl_data_pending(conn, FIRSTSOCKET);
+ Curl_conn_data_pending(data, FIRSTSOCKET);
}
/*
@@ -569,11 +488,13 @@ static CURLcode readwrite_data(struct Curl_easy *data,
result = Curl_read(data, conn->sockfd, buf, bytestoread, &nread);
/* read would've blocked */
- if(CURLE_AGAIN == result)
+ if(CURLE_AGAIN == result) {
+ result = CURLE_OK;
break; /* get out of loop */
+ }
if(result>0)
- return result;
+ goto out;
}
else {
/* read nothing but since we wanted nothing we consider this an OK
@@ -619,7 +540,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
if(conn->handler->readwrite) {
result = conn->handler->readwrite(data, conn, &nread, &readmore);
if(result)
- return result;
+ goto out;
if(readmore)
break;
}
@@ -632,13 +553,13 @@ static CURLcode readwrite_data(struct Curl_easy *data,
bool stop_reading = FALSE;
result = Curl_http_readwrite_headers(data, conn, &nread, &stop_reading);
if(result)
- return result;
+ goto out;
if(conn->handler->readwrite &&
(k->maxdownload <= 0 && nread > 0)) {
result = conn->handler->readwrite(data, conn, &nread, &readmore);
if(result)
- return result;
+ goto out;
if(readmore)
break;
}
@@ -665,11 +586,12 @@ static CURLcode readwrite_data(struct Curl_easy *data,
is non-headers. */
if(!k->header && (nread > 0 || is_empty_data)) {
- if(data->set.opt_no_body) {
+ if(data->req.no_body) {
/* data arrives although we want none, bail out */
streamclose(conn, "ignoring body");
*done = TRUE;
- return CURLE_WEIRD_SERVER_REPLY;
+ result = CURLE_WEIRD_SERVER_REPLY;
+ goto out;
}
#ifndef CURL_DISABLE_HTTP
@@ -680,7 +602,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
/* HTTP-only checks */
result = Curl_http_firstwrite(data, conn, done);
if(result || *done)
- return result;
+ goto out;
}
} /* this is the first time we write a body part */
#endif /* CURL_DISABLE_HTTP */
@@ -717,10 +639,12 @@ static CURLcode readwrite_data(struct Curl_easy *data,
if(CHUNKE_OK < res) {
if(CHUNKE_PASSTHRU_ERROR == res) {
failf(data, "Failed reading the chunked-encoded stream");
- return extra;
+ result = extra;
+ goto out;
}
failf(data, "%s in chunked-encoding", Curl_chunked_strerror(res));
- return CURLE_RECV_ERROR;
+ result = CURLE_RECV_ERROR;
+ goto out;
}
if(CHUNKE_STOP == res) {
/* we're done reading chunks! */
@@ -796,7 +720,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
(size_t)k->maxdownload);
if(result)
- return result;
+ goto out;
}
if(k->badheader < HEADER_ALLBAD) {
/* This switch handles various content encodings. If there's an
@@ -821,7 +745,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
k->badheader = HEADER_NORMAL; /* taken care of now */
if(result)
- return result;
+ goto out;
}
} /* if(!header and data to read) */
@@ -839,7 +763,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
result = conn->handler->readwrite(data, conn, &nread, &readmore);
if(result)
- return result;
+ goto out;
if(readmore)
k->keepon |= KEEP_RECV; /* we're not done reading */
@@ -874,7 +798,9 @@ static CURLcode readwrite_data(struct Curl_easy *data,
k->keepon &= ~KEEP_SEND; /* no writing anymore either */
}
- return CURLE_OK;
+out:
+ DEBUGF(infof(data, "readwrite_data(handle=%p) -> %d", data, result));
+ return result;
}
CURLcode Curl_done_sending(struct Curl_easy *data,
@@ -887,11 +813,6 @@ CURLcode Curl_done_sending(struct Curl_easy *data,
Curl_http2_done_sending(data, conn);
Curl_quic_done_sending(data);
- if(conn->bits.rewindaftersend) {
- CURLcode result = Curl_readrewind(data);
- if(result)
- return result;
- }
return CURLE_OK;
}
@@ -1201,14 +1122,15 @@ CURLcode Curl_readwrite(struct connectdata *conn,
if(select_res == CURL_CSELECT_ERR) {
failf(data, "select/poll returned error");
- return CURLE_SEND_ERROR;
+ result = CURLE_SEND_ERROR;
+ goto out;
}
#ifdef USE_HYPER
if(conn->datastream) {
result = conn->datastream(data, conn, &didwhat, done, select_res);
if(result || *done)
- return result;
+ goto out;
}
else {
#endif
@@ -1218,7 +1140,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
if((k->keepon & KEEP_RECV) && (select_res & CURL_CSELECT_IN)) {
result = readwrite_data(data, conn, k, &didwhat, done, comeback);
if(result || *done)
- return result;
+ goto out;
}
/* If we still have writing to do, we check if we have a writable socket. */
@@ -1227,7 +1149,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
result = readwrite_upload(data, conn, &didwhat);
if(result)
- return result;
+ goto out;
}
#ifdef USE_HYPER
}
@@ -1264,7 +1186,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
if(conn->transport == TRNSPRT_QUIC) {
result = Curl_quic_idle(data);
if(result)
- return result;
+ goto out;
}
#endif
}
@@ -1274,7 +1196,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
else
result = Curl_speedcheck(data, k->now);
if(result)
- return result;
+ goto out;
if(k->keepon) {
if(0 > Curl_timeleft(data, &k->now, FALSE)) {
@@ -1291,7 +1213,8 @@ CURLcode Curl_readwrite(struct connectdata *conn,
Curl_timediff(k->now, data->progress.t_startsingle),
k->bytecount);
}
- return CURLE_OPERATION_TIMEDOUT;
+ result = CURLE_OPERATION_TIMEDOUT;
+ goto out;
}
}
else {
@@ -1300,7 +1223,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
* returning.
*/
- if(!(data->set.opt_no_body) && (k->size != -1) &&
+ if(!(data->req.no_body) && (k->size != -1) &&
(k->bytecount != k->size) &&
#ifdef CURL_DO_LINEEND_CONV
/* Most FTP servers don't adjust their file SIZE response for CRLFs,
@@ -1312,9 +1235,10 @@ CURLcode Curl_readwrite(struct connectdata *conn,
!k->newurl) {
failf(data, "transfer closed with %" CURL_FORMAT_CURL_OFF_T
" bytes remaining to read", k->size - k->bytecount);
- return CURLE_PARTIAL_FILE;
+ result = CURLE_PARTIAL_FILE;
+ goto out;
}
- if(!(data->set.opt_no_body) && k->chunk &&
+ if(!(data->req.no_body) && k->chunk &&
(conn->chunk.state != CHUNK_STOP)) {
/*
* In chunked mode, return an error if the connection is closed prior to
@@ -1326,17 +1250,22 @@ CURLcode Curl_readwrite(struct connectdata *conn,
*
*/
failf(data, "transfer closed with outstanding read data remaining");
- return CURLE_PARTIAL_FILE;
+ result = CURLE_PARTIAL_FILE;
+ goto out;
+ }
+ if(Curl_pgrsUpdate(data)) {
+ result = CURLE_ABORTED_BY_CALLBACK;
+ goto out;
}
- if(Curl_pgrsUpdate(data))
- return CURLE_ABORTED_BY_CALLBACK;
}
/* Now update the "done" boolean we return */
*done = (0 == (k->keepon&(KEEP_RECV|KEEP_SEND|
KEEP_RECV_PAUSE|KEEP_SEND_PAUSE))) ? TRUE : FALSE;
-
- return CURLE_OK;
+ result = CURLE_OK;
+out:
+ DEBUGF(infof(data, "Curl_readwrite(handle=%p) -> %d", data, result));
+ return result;
}
/*
@@ -1367,7 +1296,6 @@ int Curl_single_getsock(struct Curl_easy *data,
/* don't include HOLD and PAUSE connections */
if((data->req.keepon & KEEP_SENDBITS) == KEEP_SEND) {
-
if((conn->sockfd != conn->writesockfd) ||
bitmap == GETSOCK_BLANK) {
/* only if they are not the same socket and we have a readable
@@ -1511,7 +1439,7 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
/*
* Set user-agent. Used for HTTP, but since we can attempt to tunnel
- * basically anything through a http proxy we can't limit this based on
+ * basically anything through an HTTP proxy we can't limit this based on
* protocol.
*/
if(data->set.str[STRING_USERAGENT]) {
@@ -1591,10 +1519,8 @@ CURLcode Curl_follow(struct Curl_easy *data,
to URL */
}
else {
- /* mark the next request as a followed location: */
- data->state.this_is_a_follow = TRUE;
-
- data->state.followlocation++; /* count location-followers */
+ data->state.followlocation++; /* count redirect-followings, including
+ auth reloads */
if(data->set.http_auto_referer) {
CURLU *u;
@@ -1743,7 +1669,7 @@ CURLcode Curl_follow(struct Curl_easy *data,
* differently based on exactly what return code there was.
*
* News from 7.10.6: we can also get here on a 401 or 407, in case we act on
- * a HTTP (proxy-) authentication scheme other than Basic.
+ * an HTTP (proxy-) authentication scheme other than Basic.
*/
switch(data->info.httpcode) {
/* 401 - Act on a WWW-Authenticate, we keep on moving and do the
@@ -1823,7 +1749,7 @@ CURLcode Curl_follow(struct Curl_easy *data,
data->state.httpreq = HTTPREQ_GET;
data->set.upload = false;
infof(data, "Switch to %s",
- data->set.opt_no_body?"HEAD":"GET");
+ data->req.no_body?"HEAD":"GET");
}
break;
case 304: /* Not Modified */
@@ -1865,7 +1791,7 @@ CURLcode Curl_retry_request(struct Curl_easy *data, char **url)
if((data->req.bytecount + data->req.headerbytecount == 0) &&
conn->bits.reuse &&
- (!data->set.opt_no_body || (conn->handler->protocol & PROTO_FAMILY_HTTP))
+ (!data->req.no_body || (conn->handler->protocol & PROTO_FAMILY_HTTP))
#ifndef CURL_DISABLE_RTSP
&& (data->set.rtspreq != RTSPREQ_RECEIVE)
#endif
@@ -1911,14 +1837,10 @@ CURLcode Curl_retry_request(struct Curl_easy *data, char **url)
transferred! */
- if(conn->handler->protocol&PROTO_FAMILY_HTTP) {
- if(data->req.writebytecount) {
- CURLcode result = Curl_readrewind(data);
- if(result) {
- Curl_safefree(*url);
- return result;
- }
- }
+ if((conn->handler->protocol&PROTO_FAMILY_HTTP) &&
+ data->req.writebytecount) {
+ data->state.rewindbeforesend = TRUE;
+ infof(data, "state.rewindbeforesend = TRUE");
}
}
return CURLE_OK;
@@ -1979,7 +1901,7 @@ Curl_setup_transfer(
Curl_pgrsSetDownloadSize(data, size);
}
/* we want header and/or body, if neither then don't do this! */
- if(k->getheader || !data->set.opt_no_body) {
+ if(k->getheader || !data->req.no_body) {
if(sockindex != -1)
k->keepon |= KEEP_RECV;
@@ -2015,6 +1937,6 @@ Curl_setup_transfer(
k->keepon |= KEEP_SEND;
}
} /* if(writesockindex != -1) */
- } /* if(k->getheader || !data->set.opt_no_body) */
+ } /* if(k->getheader || !data->req.no_body) */
}