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:
parent
7cf18b05e0
commit
9a2cbf30b8
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
@ -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 */
|
||||||
|
@ -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: */
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user