curl: count uploaded data to stop at the originally given size

Closes #11223
Fixes #11222
Reported-by: JustAnotherArchivist on github
This commit is contained in:
Daniel Stenberg 2023-05-30 13:59:17 +02:00
parent 6661bd588d
commit 1f85420a28
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
7 changed files with 33 additions and 38 deletions

View File

@ -35,6 +35,7 @@
#include "tool_cb_rea.h"
#include "tool_operate.h"
#include "tool_util.h"
#include "tool_msgs.h"
#include "memdebug.h" /* keep this as LAST include */
@ -45,12 +46,18 @@
size_t tool_read_cb(char *buffer, size_t sz, size_t nmemb, void *userdata)
{
ssize_t rc = 0;
struct InStruct *in = userdata;
struct OperationConfig *config = in->config;
struct per_transfer *per = userdata;
struct OperationConfig *config = per->config;
if((per->uploadfilesize != -1) &&
(per->uploadedsofar == per->uploadfilesize)) {
/* done */
return 0;
}
if(config->timeout_ms) {
struct timeval now = tvnow();
long msdelta = tvdiff(now, in->per->start);
long msdelta = tvdiff(now, per->start);
if(msdelta > config->timeout_ms)
/* timeout */
@ -68,24 +75,33 @@ size_t tool_read_cb(char *buffer, size_t sz, size_t nmemb, void *userdata)
timeout.tv_usec = (int)((wait%1000)*1000);
FD_ZERO(&bits);
FD_SET(in->fd, &bits);
if(!select(in->fd + 1, &bits, NULL, NULL, &timeout))
FD_SET(per->infd, &bits);
if(!select(per->infd + 1, &bits, NULL, NULL, &timeout))
return 0; /* timeout */
}
#endif
}
rc = read(in->fd, buffer, sz*nmemb);
rc = read(per->infd, buffer, sz*nmemb);
if(rc < 0) {
if(errno == EAGAIN) {
errno = 0;
in->config->readbusy = TRUE;
config->readbusy = TRUE;
return CURL_READFUNC_PAUSE;
}
/* since size_t is unsigned we can't return negative values fine */
rc = 0;
}
in->config->readbusy = FALSE;
if((per->uploadfilesize != -1) &&
(per->uploadedsofar + rc > per->uploadfilesize)) {
/* do not allow uploading more than originally set out to do */
curl_off_t delta = per->uploadedsofar + rc - per->uploadfilesize;
warnf(per->config->global, "File size larger in the end than when "
"started. Dropping at least %" CURL_FORMAT_CURL_OFF_T " bytes",
delta);
rc = (ssize_t)(per->uploadfilesize - per->uploadedsofar);
}
config->readbusy = FALSE;
/* when select() returned zero here, it timed out */
return (size_t)rc;

View File

@ -28,6 +28,7 @@
#include "curlx.h"
#include "tool_cfgable.h"
#include "tool_operate.h"
#include "tool_cb_see.h"
#include "memdebug.h" /* keep this as LAST include */
@ -48,7 +49,7 @@
int tool_seek_cb(void *userdata, curl_off_t offset, int whence)
{
struct InStruct *in = userdata;
struct per_transfer *per = userdata;
#if(SIZEOF_CURL_OFF_T > SIZEOF_OFF_T) && !defined(USE_WIN32_LARGE_FILES)
@ -81,7 +82,7 @@ int tool_seek_cb(void *userdata, curl_off_t offset, int whence)
}
#endif
if(LSEEK_ERROR == lseek(in->fd, offset, whence))
if(LSEEK_ERROR == lseek(per->infd, offset, whence))
/* couldn't rewind, the reason is in errno but errno is just not portable
enough and we don't actually care that much why we failed. We'll let
libcurl know that it may try other means if it wants to. */

View File

@ -24,6 +24,7 @@
#include "tool_setup.h"
#include "tool_cfgable.h"
#include "tool_formparse.h"
#include "tool_main.h"
#include "memdebug.h" /* keep this as LAST include */

View File

@ -26,7 +26,6 @@
#include "tool_setup.h"
#include "tool_sdecls.h"
#include "tool_urlglob.h"
#include "tool_formparse.h"
struct GlobalConfig;

View File

@ -327,8 +327,8 @@ static CURLcode pre_transfer(struct GlobalConfig *global,
#endif
my_setopt(per->curl, CURLOPT_INFILESIZE_LARGE, uploadfilesize);
}
per->input.fd = per->infd;
}
per->uploadfilesize = uploadfilesize;
per->start = tvnow();
return result;
}
@ -845,7 +845,6 @@ static CURLcode single_transfer(struct GlobalConfig *global,
if(state->up < state->infilenum) {
struct per_transfer *per = NULL;
struct OutStruct *outs;
struct InStruct *input;
struct OutStruct *heads;
struct OutStruct *etag_save;
struct HdrCbData *hdrcbdata = NULL;
@ -1004,7 +1003,6 @@ static CURLcode single_transfer(struct GlobalConfig *global,
hdrcbdata = &per->hdrcbdata;
outs = &per->outs;
input = &per->input;
per->outfile = NULL;
per->infdopen = FALSE;
@ -1274,9 +1272,6 @@ static CURLcode single_transfer(struct GlobalConfig *global,
/* what call to write */
my_setopt(curl, CURLOPT_WRITEFUNCTION, tool_write_cb);
/* for uploads */
input->config = config;
input->per = per;
/* Note that if CURLOPT_READFUNCTION is fread (the default), then
* lib/telnet.c will Curl_poll() on the input file descriptor
* rather than calling the READFUNCTION at regular intervals.
@ -1284,13 +1279,13 @@ static CURLcode single_transfer(struct GlobalConfig *global,
* behavior, by omitting to set the READFUNCTION & READDATA options,
* have not been determined.
*/
my_setopt(curl, CURLOPT_READDATA, input);
my_setopt(curl, CURLOPT_READDATA, per);
/* what call to read */
my_setopt(curl, CURLOPT_READFUNCTION, tool_read_cb);
/* in 7.18.0, the CURLOPT_SEEKFUNCTION/DATA pair is taking over what
CURLOPT_IOCTLFUNCTION/DATA pair previously provided for seeking */
my_setopt(curl, CURLOPT_SEEKDATA, input);
my_setopt(curl, CURLOPT_SEEKDATA, per);
my_setopt(curl, CURLOPT_SEEKFUNCTION, tool_seek_cb);
{

View File

@ -50,7 +50,6 @@ struct per_transfer {
struct OutStruct outs;
struct OutStruct heads;
struct OutStruct etag_save;
struct InStruct input;
struct HdrCbData hdrcbdata;
long num_headers;
bool was_last_header_empty;
@ -68,6 +67,8 @@ struct per_transfer {
curl_off_t dlnow;
curl_off_t ultotal;
curl_off_t ulnow;
curl_off_t uploadfilesize; /* expected total amount */
curl_off_t uploadedsofar; /* amount delivered from the callback */
bool dltotal_added; /* if the total has been added from this */
bool ultotal_added;

View File

@ -70,24 +70,6 @@ struct OutStruct {
curl_off_t init;
};
/*
* InStruct variables keep track of information relative to curl's
* input reading, which may take place from stdin or from some file.
*
* 'fd' member is either 'stdin' file descriptor number STDIN_FILENO
* or a file descriptor as returned from an 'open' call for some file.
*
* 'config' member is a pointer to associated 'OperationConfig' struct.
*/
struct InStruct {
int fd;
struct OperationConfig *config;
struct per_transfer *per;
};
/*
* A linked list of these 'getout' nodes contain URL's to fetch,
* as well as information relative to where URL contents should