summaryrefslogtreecommitdiff
path: root/libs/libcurl/src/transfer.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/libcurl/src/transfer.c')
-rw-r--r--libs/libcurl/src/transfer.c249
1 files changed, 143 insertions, 106 deletions
diff --git a/libs/libcurl/src/transfer.c b/libs/libcurl/src/transfer.c
index 257932b0fa..b21ada91a5 100644
--- a/libs/libcurl/src/transfer.c
+++ b/libs/libcurl/src/transfer.c
@@ -53,7 +53,7 @@
#endif
#ifndef HAVE_SOCKET
-#error "We can't compile without socket() support!"
+#error "We cannot compile without socket() support!"
#endif
#include "urldata.h"
@@ -160,6 +160,30 @@ bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc)
return TRUE;
}
+static CURLcode xfer_recv_shutdown(struct Curl_easy *data, bool *done)
+{
+ int sockindex;
+
+ if(!data || !data->conn)
+ return CURLE_FAILED_INIT;
+ if(data->conn->sockfd == CURL_SOCKET_BAD)
+ return CURLE_FAILED_INIT;
+ sockindex = (data->conn->sockfd == data->conn->sock[SECONDARYSOCKET]);
+ return Curl_conn_shutdown(data, sockindex, done);
+}
+
+static bool xfer_recv_shutdown_started(struct Curl_easy *data)
+{
+ int sockindex;
+
+ if(!data || !data->conn)
+ return CURLE_FAILED_INIT;
+ if(data->conn->sockfd == CURL_SOCKET_BAD)
+ return CURLE_FAILED_INIT;
+ sockindex = (data->conn->sockfd == data->conn->sock[SECONDARYSOCKET]);
+ return Curl_shutdown_started(data, sockindex);
+}
+
/**
* Receive raw response data for the transfer.
* @param data the transfer
@@ -186,17 +210,35 @@ static ssize_t Curl_xfer_recv_resp(struct Curl_easy *data,
else if(totalleft < (curl_off_t)blen)
blen = (size_t)totalleft;
}
+ else if(xfer_recv_shutdown_started(data)) {
+ /* we already reveived everything. Do not try more. */
+ blen = 0;
+ }
if(!blen) {
- /* want nothing - continue as if read nothing. */
- DEBUGF(infof(data, "readwrite_data: we're done"));
+ /* want nothing more */
*err = CURLE_OK;
- return 0;
+ nread = 0;
+ }
+ else {
+ *err = Curl_xfer_recv(data, buf, blen, &nread);
}
- *err = Curl_xfer_recv(data, buf, blen, &nread);
if(*err)
return -1;
+ if(nread == 0) {
+ if(data->req.shutdown) {
+ bool done;
+ *err = xfer_recv_shutdown(data, &done);
+ if(*err)
+ return -1;
+ if(!done) {
+ *err = CURLE_AGAIN;
+ return -1;
+ }
+ }
+ DEBUGF(infof(data, "readwrite_data: we are done"));
+ }
DEBUGASSERT(nread >= 0);
return nread;
}
@@ -271,7 +313,10 @@ static CURLcode readwrite_data(struct Curl_easy *data,
DEBUGF(infof(data, "nread == 0, stream closed, bailing"));
else
DEBUGF(infof(data, "nread <= 0, server closed connection, bailing"));
- k->keepon &= ~(KEEP_RECV|KEEP_SEND); /* stop sending as well */
+ /* stop receiving and ALL sending as well, including PAUSE and HOLD.
+ * We might still be paused on receive client writes though, so
+ * keep those bits around. */
+ k->keepon &= ~(KEEP_RECV|KEEP_SENDBITS);
if(k->eos_written) /* already did write this to client, leave */
break;
}
@@ -291,10 +336,11 @@ static CURLcode readwrite_data(struct Curl_easy *data,
if((k->keepon & KEEP_RECV_PAUSE) || !(k->keepon & KEEP_RECV))
break;
- } while(maxloops-- && data_pending(data));
+ } while(maxloops--);
- if(maxloops <= 0) {
- /* did not read until EAGAIN, mark read-again-please */
+ if((maxloops <= 0) || data_pending(data)) {
+ /* did not read until EAGAIN or there is still pending data, mark as
+ read-again-please */
data->state.select_bits = CURL_CSELECT_IN;
if((k->keepon & KEEP_SENDBITS) == KEEP_SEND)
data->state.select_bits |= CURL_CSELECT_OUT;
@@ -302,8 +348,8 @@ static CURLcode readwrite_data(struct Curl_easy *data,
if(((k->keepon & (KEEP_RECV|KEEP_SEND)) == KEEP_SEND) &&
(conn->bits.close || is_multiplex)) {
- /* When we've read the entire thing and the close bit is set, the server
- may now close the connection. If there's now any kind of sending going
+ /* When we have read the entire thing and the close bit is set, the server
+ may now close the connection. If there is now any kind of sending going
on from our side, we need to stop that immediately. */
infof(data, "we are done reading and this is set to close, stop send");
k->keepon &= ~KEEP_SEND; /* no writing anymore either */
@@ -317,37 +363,11 @@ out:
return result;
}
-#if defined(_WIN32) && defined(USE_WINSOCK)
-#ifndef SIO_IDEAL_SEND_BACKLOG_QUERY
-#define SIO_IDEAL_SEND_BACKLOG_QUERY 0x4004747B
-#endif
-
-static void win_update_buffer_size(curl_socket_t sockfd)
-{
- int result;
- ULONG ideal;
- DWORD ideallen;
- result = WSAIoctl(sockfd, SIO_IDEAL_SEND_BACKLOG_QUERY, 0, 0,
- &ideal, sizeof(ideal), &ideallen, 0, 0);
- if(result == 0) {
- setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF,
- (const char *)&ideal, sizeof(ideal));
- }
-}
-#else
-#define win_update_buffer_size(x)
-#endif
-
-#define curl_upload_refill_watermark(data) \
- ((size_t)((data)->set.upload_buffer_size >> 5))
-
/*
* Send data to upload to the server, when the socket is writable.
*/
static CURLcode readwrite_upload(struct Curl_easy *data, int *didwhat)
{
- CURLcode result = CURLE_OK;
-
if((data->req.keepon & KEEP_SEND_PAUSE))
return CURLE_OK;
@@ -358,23 +378,9 @@ static CURLcode readwrite_upload(struct Curl_easy *data, int *didwhat)
if(!Curl_req_done_sending(data)) {
*didwhat |= KEEP_SEND;
- result = Curl_req_send_more(data);
- if(result)
- return result;
-
-#if defined(_WIN32) && defined(USE_WINSOCK)
- /* FIXME: this looks like it would fit better into cf-socket.c
- * but then I do not know enough Windows to say... */
- {
- struct curltime n = Curl_now();
- if(Curl_timediff(n, data->conn->last_sndbuf_update) > 1000) {
- win_update_buffer_size(data->conn->writesockfd);
- data->conn->last_sndbuf_update = n;
- }
- }
-#endif
+ return Curl_req_send_more(data);
}
- return result;
+ return CURLE_OK;
}
static int select_bits_paused(struct Curl_easy *data, int select_bits)
@@ -408,14 +414,6 @@ CURLcode Curl_readwrite(struct Curl_easy *data)
int didwhat = 0;
int select_bits;
- /* Check if client writes had been paused and can resume now. */
- if(!(k->keepon & KEEP_RECV_PAUSE) && Curl_cwriter_is_paused(data)) {
- Curl_conn_ev_data_pause(data, FALSE);
- result = Curl_cwriter_unpause(data);
- if(result)
- goto out;
- }
-
if(data->state.select_bits) {
if(select_bits_paused(data, data->state.select_bits)) {
/* leave the bits unchanged, so they'll tell us what to do when
@@ -522,9 +520,9 @@ CURLcode Curl_readwrite(struct Curl_easy *data)
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,
- so we'll check to see if the discrepancy can be explained
- by the number of CRLFs we've changed to LFs.
+ /* Most FTP servers do not adjust their file SIZE response for CRLFs,
+ so we will check to see if the discrepancy can be explained
+ by the number of CRLFs we have changed to LFs.
*/
(k->bytecount != (k->size + data->state.crlf_conversions)) &&
#endif /* CURL_DO_LINEEND_CONV */
@@ -569,7 +567,7 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
CURLcode result;
if(!data->state.url && !data->set.uh) {
- /* we can't do anything without URL */
+ /* we cannot do anything without URL */
failf(data, "No URL set");
return CURLE_URL_MALFORMAT;
}
@@ -593,7 +591,7 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
}
if(data->set.postfields && data->set.set_resume_from) {
- /* we can't */
+ /* we cannot */
failf(data, "cannot mix POSTFIELDS with RESUME_FROM");
return CURLE_BAD_FUNCTION_ARGUMENT;
}
@@ -695,7 +693,7 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
/*
* Set user-agent. Used for HTTP, but since we can attempt to tunnel
- * basically anything through an HTTP proxy we can't limit this based on
+ * basically anything through an HTTP proxy we cannot limit this based on
* protocol.
*/
if(data->set.str[STRING_USERAGENT]) {
@@ -727,22 +725,6 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
}
/*
- * Curl_posttransfer() is called immediately after a transfer ends
- */
-CURLcode Curl_posttransfer(struct Curl_easy *data)
-{
-#if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(HAVE_MSG_NOSIGNAL)
- /* restore the signal handler for SIGPIPE before we get back */
- if(!data->set.no_signal)
- signal(SIGPIPE, data->state.prev_signal);
-#else
- (void)data; /* unused parameter */
-#endif
-
- return CURLE_OK;
-}
-
-/*
* Curl_follow() handles the URL redirect magic. Pass in the 'newurl' string
* as given by the remote server and set up the new URL to request.
*
@@ -823,16 +805,16 @@ CURLcode Curl_follow(struct Curl_easy *data,
(data->req.httpcode != 401) && (data->req.httpcode != 407) &&
Curl_is_absolute_url(newurl, NULL, 0, FALSE)) {
/* If this is not redirect due to a 401 or 407 response and an absolute
- URL: don't allow a custom port number */
+ URL: do not allow a custom port number */
disallowport = TRUE;
}
DEBUGASSERT(data->state.uh);
- uc = curl_url_set(data->state.uh, CURLUPART_URL, newurl,
- (type == FOLLOW_FAKE) ? CURLU_NON_SUPPORT_SCHEME :
- ((type == FOLLOW_REDIR) ? CURLU_URLENCODE : 0) |
- CURLU_ALLOW_SPACE |
- (data->set.path_as_is ? CURLU_PATH_AS_IS : 0));
+ uc = curl_url_set(data->state.uh, CURLUPART_URL, newurl, (unsigned int)
+ ((type == FOLLOW_FAKE) ? CURLU_NON_SUPPORT_SCHEME :
+ ((type == FOLLOW_REDIR) ? CURLU_URLENCODE : 0) |
+ CURLU_ALLOW_SPACE |
+ (data->set.path_as_is ? CURLU_PATH_AS_IS : 0)));
if(uc) {
if(type != FOLLOW_FAKE) {
failf(data, "The redirect target URL could not be parsed: %s",
@@ -901,8 +883,8 @@ CURLcode Curl_follow(struct Curl_easy *data,
}
if(type == FOLLOW_FAKE) {
- /* we're only figuring out the new url if we would've followed locations
- but now we're done so we can get out! */
+ /* we are only figuring out the new URL if we would have followed locations
+ but now we are done so we can get out! */
data->info.wouldredirect = newurl;
if(reachedmax) {
@@ -939,15 +921,15 @@ CURLcode Curl_follow(struct Curl_easy *data,
/* 306 - Not used */
/* 307 - Temporary Redirect */
default: /* for all above (and the unknown ones) */
- /* Some codes are explicitly mentioned since I've checked RFC2616 and they
- * seem to be OK to POST to.
+ /* Some codes are explicitly mentioned since I have checked RFC2616 and
+ * they seem to be OK to POST to.
*/
break;
case 301: /* Moved Permanently */
/* (quote from RFC7231, section 6.4.2)
*
* Note: For historical reasons, a user agent MAY change the request
- * method from POST to GET for the subsequent request. If this
+ * method from POST to GET for the subsequent request. If this
* behavior is undesired, the 307 (Temporary Redirect) status code
* can be used instead.
*
@@ -973,7 +955,7 @@ CURLcode Curl_follow(struct Curl_easy *data,
/* (quote from RFC7231, section 6.4.3)
*
* Note: For historical reasons, a user agent MAY change the request
- * method from POST to GET for the subsequent request. If this
+ * method from POST to GET for the subsequent request. If this
* behavior is undesired, the 307 (Temporary Redirect) status code
* can be used instead.
*
@@ -1014,14 +996,14 @@ CURLcode Curl_follow(struct Curl_easy *data,
break;
case 304: /* Not Modified */
/* 304 means we did a conditional request and it was "Not modified".
- * We shouldn't get any Location: header in this response!
+ * We should not get any Location: header in this response!
*/
break;
case 305: /* Use Proxy */
/* (quote from RFC2616, section 10.3.6):
* "The requested resource MUST be accessed through the proxy given
* by the Location field. The Location field gives the URI of the
- * proxy. The recipient is expected to repeat this single request
+ * proxy. The recipient is expected to repeat this single request
* via the proxy. 305 responses MUST only be generated by origin
* servers."
*/
@@ -1043,8 +1025,9 @@ CURLcode Curl_retry_request(struct Curl_easy *data, char **url)
bool retry = FALSE;
*url = NULL;
- /* if we're talking upload, we can't do the checks below, unless the protocol
- is HTTP as when uploading over HTTP we will still get a response */
+ /* if we are talking upload, we cannot do the checks below, unless the
+ protocol is HTTP as when uploading over HTTP we will still get a
+ response */
if(data->state.upload &&
!(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP)))
return CURLE_OK;
@@ -1090,7 +1073,7 @@ CURLcode Curl_retry_request(struct Curl_easy *data, char **url)
return CURLE_OUT_OF_MEMORY;
connclose(conn, "retry"); /* close this connection */
- conn->bits.retry = TRUE; /* mark this as a connection we're about
+ conn->bits.retry = TRUE; /* mark this as a connection we are about
to retry. Marking it this way should
prevent i.e HTTP transfers to return
error just because nothing has been
@@ -1101,16 +1084,17 @@ CURLcode Curl_retry_request(struct Curl_easy *data, char **url)
}
/*
- * Curl_xfer_setup() is called to setup some basic properties for the
- * upcoming transfer.
+ * xfer_setup() is called to setup basic properties for the transfer.
*/
-void Curl_xfer_setup(
+static void xfer_setup(
struct Curl_easy *data, /* transfer */
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 */
- int writesockindex /* socket index to write to, it may very well be
+ int writesockindex, /* socket index to write to, it may very well be
the same we read from. -1 disables */
+ bool shutdown /* shutdown connection at transfer end. Only
+ * supported when sending OR receiving. */
)
{
struct SingleRequest *k = &data->req;
@@ -1120,6 +1104,7 @@ void Curl_xfer_setup(
DEBUGASSERT(conn != NULL);
DEBUGASSERT((sockindex <= 1) && (sockindex >= -1));
DEBUGASSERT((writesockindex <= 1) && (writesockindex >= -1));
+ DEBUGASSERT(!shutdown || (sockindex == -1) || (writesockindex == -1));
if(conn->bits.multiplex || conn->httpversion >= 20 || want_send) {
/* when multiplexing, the read/write sockets need to be the same! */
@@ -1137,9 +1122,10 @@ void Curl_xfer_setup(
conn->writesockfd = writesockindex == -1 ?
CURL_SOCKET_BAD:conn->sock[writesockindex];
}
- k->getheader = getheader;
+ k->getheader = getheader;
k->size = size;
+ k->shutdown = shutdown;
/* The code sequence below is placed in this function just because all
necessary input is not always known in do_complete() as this function may
@@ -1150,7 +1136,7 @@ void Curl_xfer_setup(
if(size > 0)
Curl_pgrsSetDownloadSize(data, size);
}
- /* we want header and/or body, if neither then don't do this! */
+ /* we want header and/or body, if neither then do not do this! */
if(k->getheader || !data->req.no_body) {
if(sockindex != -1)
@@ -1162,6 +1148,33 @@ void Curl_xfer_setup(
}
+void Curl_xfer_setup_nop(struct Curl_easy *data)
+{
+ xfer_setup(data, -1, -1, FALSE, -1, FALSE);
+}
+
+void Curl_xfer_setup1(struct Curl_easy *data,
+ int send_recv,
+ curl_off_t recv_size,
+ bool getheader)
+{
+ int recv_index = (send_recv & CURL_XFER_RECV)? FIRSTSOCKET : -1;
+ int send_index = (send_recv & CURL_XFER_SEND)? FIRSTSOCKET : -1;
+ DEBUGASSERT((recv_index >= 0) || (recv_size == -1));
+ xfer_setup(data, recv_index, recv_size, getheader, send_index, FALSE);
+}
+
+void Curl_xfer_setup2(struct Curl_easy *data,
+ int send_recv,
+ curl_off_t recv_size,
+ bool shutdown)
+{
+ int recv_index = (send_recv & CURL_XFER_RECV)? SECONDARYSOCKET : -1;
+ int send_index = (send_recv & CURL_XFER_SEND)? SECONDARYSOCKET : -1;
+ DEBUGASSERT((recv_index >= 0) || (recv_size == -1));
+ xfer_setup(data, recv_index, recv_size, FALSE, send_index, shutdown);
+}
+
CURLcode Curl_xfer_write_resp(struct Curl_easy *data,
const char *buf, size_t blen,
bool is_eos)
@@ -1276,3 +1289,27 @@ CURLcode Curl_xfer_send_close(struct Curl_easy *data)
Curl_conn_ev_data_done_send(data);
return CURLE_OK;
}
+
+CURLcode Curl_xfer_send_shutdown(struct Curl_easy *data, bool *done)
+{
+ int sockindex;
+
+ if(!data || !data->conn)
+ return CURLE_FAILED_INIT;
+ if(data->conn->writesockfd == CURL_SOCKET_BAD)
+ return CURLE_FAILED_INIT;
+ sockindex = (data->conn->writesockfd == data->conn->sock[SECONDARYSOCKET]);
+ return Curl_conn_shutdown(data, sockindex, done);
+}
+
+bool Curl_xfer_is_blocked(struct Curl_easy *data)
+{
+ bool want_send = ((data)->req.keepon & KEEP_SEND);
+ bool want_recv = ((data)->req.keepon & KEEP_RECV);
+ if(!want_send)
+ return (want_recv && Curl_cwriter_is_paused(data));
+ else if(!want_recv)
+ return (want_send && Curl_creader_is_paused(data));
+ else
+ return Curl_creader_is_paused(data) && Curl_cwriter_is_paused(data);
+}