diff options
Diffstat (limited to 'Utilities/cmcurl/lib/transfer.c')
-rw-r--r-- | Utilities/cmcurl/lib/transfer.c | 198 |
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) */ } |