1
0
mirror of https://github.com/moparisthebest/curl synced 2025-01-10 21:48:10 -05:00

curl: fix --upload-file . hangs if delay in STDIN

Attempt to unpause a busy read in the CURLOPT_XFERINFOFUNCTION.

When uploading from stdin in non-blocking mode, a delay in reading
the stream (EAGAIN) causes curl to pause sending data
(CURL_READFUNC_PAUSE).  Prior to this change, a busy read was
detected and unpaused only in the CURLOPT_WRITEFUNCTION handler.
This change performs the same busy read handling in a
CURLOPT_XFERINFOFUNCTION handler.

Fixes #2051
Closes #4599
Reported-by: bdry on github
This commit is contained in:
John Schroeder 2019-11-26 09:16:19 +01:00 committed by Daniel Stenberg
parent 7cf18b05e0
commit 9a2cbf30b8
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
6 changed files with 63 additions and 4 deletions

View File

@ -32,6 +32,7 @@
#include "tool_cfgable.h" #include "tool_cfgable.h"
#include "tool_cb_prg.h" #include "tool_cb_prg.h"
#include "tool_util.h" #include "tool_util.h"
#include "tool_operate.h"
#include "memdebug.h" /* keep this as LAST include */ #include "memdebug.h" /* keep this as LAST include */
@ -121,7 +122,10 @@ int tool_progress_cb(void *clientp,
and this new edition inherits some of his concepts. */ and this new edition inherits some of his concepts. */
struct timeval now = tvnow(); struct timeval now = tvnow();
struct ProgressData *bar = (struct ProgressData *)clientp; struct per_transfer *per = clientp;
struct OutStruct *outs = &per->outs;
struct OperationConfig *config = outs->config;
struct ProgressData *bar = &per->progressbar;
curl_off_t total; curl_off_t total;
curl_off_t point; curl_off_t point;
@ -191,6 +195,11 @@ int tool_progress_cb(void *clientp,
bar->prev = point; bar->prev = point;
bar->prevtime = now; bar->prevtime = now;
if(config->readbusy) {
config->readbusy = FALSE;
curl_easy_pause(per->curl, CURLPAUSE_CONT);
}
return 0; return 0;
} }

View File

@ -27,6 +27,7 @@
#include "tool_cfgable.h" #include "tool_cfgable.h"
#include "tool_cb_rea.h" #include "tool_cb_rea.h"
#include "tool_operate.h"
#include "memdebug.h" /* keep this as LAST include */ #include "memdebug.h" /* keep this as LAST include */
@ -52,3 +53,28 @@ size_t tool_read_cb(void *buffer, size_t sz, size_t nmemb, void *userdata)
in->config->readbusy = FALSE; in->config->readbusy = FALSE;
return (size_t)rc; return (size_t)rc;
} }
/*
** callback for CURLOPT_XFERINFOFUNCTION used to unpause busy reads
*/
int tool_readbusy_cb(void *clientp,
curl_off_t dltotal, curl_off_t dlnow,
curl_off_t ultotal, curl_off_t ulnow)
{
struct per_transfer *per = clientp;
struct OutStruct *outs = &per->outs;
struct OperationConfig *config = outs->config;
(void)dltotal; /* unused */
(void)dlnow; /* unused */
(void)ultotal; /* unused */
(void)ulnow; /* unused */
if(config->readbusy) {
config->readbusy = FALSE;
curl_easy_pause(per->curl, CURLPAUSE_CONT);
}
return per->noprogress? 0 : CURL_PROGRESSFUNC_CONTINUE;
}

View File

@ -29,4 +29,12 @@
size_t tool_read_cb(void *buffer, size_t sz, size_t nmemb, void *userdata); size_t tool_read_cb(void *buffer, size_t sz, size_t nmemb, void *userdata);
/*
** callback for CURLOPT_XFERINFOFUNCTION used to unpause busy reads
*/
int tool_readbusy_cb(void *clientp,
curl_off_t dltotal, curl_off_t dlnow,
curl_off_t ultotal, curl_off_t ulnow);
#endif /* HEADER_CURL_TOOL_CB_REA_H */ #endif /* HEADER_CURL_TOOL_CB_REA_H */

View File

@ -1080,11 +1080,11 @@ static CURLcode single_transfer(struct GlobalConfig *global,
isatty(fileno(outs->stream))) isatty(fileno(outs->stream)))
/* we send the output to a tty, therefore we switch off the progress /* we send the output to a tty, therefore we switch off the progress
meter */ meter */
global->noprogress = global->isatty = TRUE; per->noprogress = global->noprogress = global->isatty = TRUE;
else { else {
/* progress meter is per download, so restore config /* progress meter is per download, so restore config
values */ values */
global->noprogress = orig_noprogress; per->noprogress = global->noprogress = orig_noprogress;
global->isatty = orig_isatty; global->isatty = orig_isatty;
} }
@ -1573,7 +1573,14 @@ static CURLcode single_transfer(struct GlobalConfig *global,
/* we want the alternative style, then we have to implement it /* we want the alternative style, then we have to implement it
ourselves! */ ourselves! */
my_setopt(curl, CURLOPT_XFERINFOFUNCTION, tool_progress_cb); my_setopt(curl, CURLOPT_XFERINFOFUNCTION, tool_progress_cb);
my_setopt(curl, CURLOPT_XFERINFODATA, &per->progressbar); my_setopt(curl, CURLOPT_XFERINFODATA, per);
}
else if(per->uploadfile && !strcmp(per->uploadfile, ".")) {
/* when reading from stdin in non-blocking mode, we use the progress
function to unpause a busy read */
my_setopt(curl, CURLOPT_NOPROGRESS, 0L);
my_setopt(curl, CURLOPT_XFERINFOFUNCTION, tool_readbusy_cb);
my_setopt(curl, CURLOPT_XFERINFODATA, per);
} }
/* new in libcurl 7.24.0: */ /* new in libcurl 7.24.0: */

View File

@ -44,6 +44,7 @@ struct per_transfer {
char *outfile; char *outfile;
bool infdopen; /* TRUE if infd needs closing */ bool infdopen; /* TRUE if infd needs closing */
int infd; int infd;
bool noprogress;
struct ProgressData progressbar; struct ProgressData progressbar;
struct OutStruct outs; struct OutStruct outs;
struct OutStruct heads; struct OutStruct heads;

View File

@ -95,10 +95,18 @@ int xferinfo_cb(void *clientp,
curl_off_t ulnow) curl_off_t ulnow)
{ {
struct per_transfer *per = clientp; struct per_transfer *per = clientp;
struct OutStruct *outs = &per->outs;
struct OperationConfig *config = outs->config;
per->dltotal = dltotal; per->dltotal = dltotal;
per->dlnow = dlnow; per->dlnow = dlnow;
per->ultotal = ultotal; per->ultotal = ultotal;
per->ulnow = ulnow; per->ulnow = ulnow;
if(config->readbusy) {
config->readbusy = FALSE;
curl_easy_pause(per->curl, CURLPAUSE_CONT);
}
return 0; return 0;
} }