mirror of
https://github.com/moparisthebest/curl
synced 2024-12-22 16:18:48 -05:00
allow write callbacks to indicate OOM to libcurl
Allow (*curl_write_callback) write callbacks to return CURL_WRITEFUNC_OUT_OF_MEMORY to properly indicate libcurl of OOM conditions inside the callback itself.
This commit is contained in:
parent
e276802ff8
commit
119f43360b
@ -160,6 +160,11 @@ From 7.18.0, the function can return CURL_WRITEFUNC_PAUSE which then will
|
|||||||
cause writing to this connection to become paused. See
|
cause writing to this connection to become paused. See
|
||||||
\fIcurl_easy_pause(3)\fP for further details.
|
\fIcurl_easy_pause(3)\fP for further details.
|
||||||
|
|
||||||
|
From 7.22.1, the function can return CURL_WRITEFUNC_OUT_OF_MEMORY to indicate
|
||||||
|
libcurl that an attempt to dynamically allocate memory from within the write
|
||||||
|
callback itself has failed. This will abort the transfer and make libcurl
|
||||||
|
return CURLE_OUT_OF_MEMORY.
|
||||||
|
|
||||||
This function may be called with zero bytes data if the transferred file is
|
This function may be called with zero bytes data if the transferred file is
|
||||||
empty.
|
empty.
|
||||||
|
|
||||||
|
@ -685,4 +685,5 @@ CURL_VERSION_SPNEGO 7.10.8
|
|||||||
CURL_VERSION_SSL 7.10
|
CURL_VERSION_SSL 7.10
|
||||||
CURL_VERSION_SSPI 7.13.2
|
CURL_VERSION_SSPI 7.13.2
|
||||||
CURL_VERSION_TLSAUTH_SRP 7.21.4
|
CURL_VERSION_TLSAUTH_SRP 7.21.4
|
||||||
|
CURL_WRITEFUNC_OUT_OF_MEMORY 7.22.1
|
||||||
CURL_WRITEFUNC_PAUSE 7.18.0
|
CURL_WRITEFUNC_PAUSE 7.18.0
|
||||||
|
@ -187,10 +187,15 @@ typedef int (*curl_progress_callback)(void *clientp,
|
|||||||
#define CURL_MAX_HTTP_HEADER (100*1024)
|
#define CURL_MAX_HTTP_HEADER (100*1024)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* This is a magic return code for the write callback that, when returned,
|
/* This is a magic return code for the write callback that, when returned,
|
||||||
will signal libcurl to pause receiving on the current transfer. */
|
will signal libcurl to pause receiving on the current transfer. */
|
||||||
#define CURL_WRITEFUNC_PAUSE 0x10000001
|
#define CURL_WRITEFUNC_PAUSE 0x10000001
|
||||||
|
|
||||||
|
/* If the write callback itself allocates memory dynamically and this fails
|
||||||
|
due to an out of memory condition, returning CURL_WRITEFUNC_OUT_OF_MEMORY
|
||||||
|
is the proper way to tell libcurl of this condition. */
|
||||||
|
#define CURL_WRITEFUNC_OUT_OF_MEMORY 0x10000002
|
||||||
|
|
||||||
typedef size_t (*curl_write_callback)(char *buffer,
|
typedef size_t (*curl_write_callback)(char *buffer,
|
||||||
size_t size,
|
size_t size,
|
||||||
size_t nitems,
|
size_t nitems,
|
||||||
|
@ -354,6 +354,8 @@ static CURLcode ftp_pl_insert_finfo(struct connectdata *conn,
|
|||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Curl_ftp_parselist is a write callback function */
|
||||||
|
|
||||||
size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
|
size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
|
||||||
void *connptr)
|
void *connptr)
|
||||||
{
|
{
|
||||||
@ -365,6 +367,10 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
|
|||||||
unsigned long i = 0;
|
unsigned long i = 0;
|
||||||
CURLcode rc;
|
CURLcode rc;
|
||||||
|
|
||||||
|
if(bufflen >= CURL_WRITEFUNC_PAUSE)
|
||||||
|
/* CURL_WRITEFUNC_PAUSE limits input size */
|
||||||
|
return CURL_WRITEFUNC_OUT_OF_MEMORY;
|
||||||
|
|
||||||
if(parser->error) { /* error in previous call */
|
if(parser->error) { /* error in previous call */
|
||||||
/* scenario:
|
/* scenario:
|
||||||
* 1. call => OK..
|
* 1. call => OK..
|
||||||
@ -372,6 +378,9 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
|
|||||||
* 3. (last) call => is skipped RIGHT HERE and the error is hadled later
|
* 3. (last) call => is skipped RIGHT HERE and the error is hadled later
|
||||||
* in wc_statemach()
|
* in wc_statemach()
|
||||||
*/
|
*/
|
||||||
|
if(parser->error == CURLE_OUT_OF_MEMORY)
|
||||||
|
return CURL_WRITEFUNC_OUT_OF_MEMORY;
|
||||||
|
|
||||||
return bufflen;
|
return bufflen;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -388,12 +397,12 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
|
|||||||
parser->file_data = Curl_fileinfo_alloc();
|
parser->file_data = Curl_fileinfo_alloc();
|
||||||
if(!parser->file_data) {
|
if(!parser->file_data) {
|
||||||
parser->error = CURLE_OUT_OF_MEMORY;
|
parser->error = CURLE_OUT_OF_MEMORY;
|
||||||
return bufflen;
|
return CURL_WRITEFUNC_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
parser->file_data->b_data = malloc(FTP_BUFFER_ALLOCSIZE);
|
parser->file_data->b_data = malloc(FTP_BUFFER_ALLOCSIZE);
|
||||||
if(!parser->file_data->b_data) {
|
if(!parser->file_data->b_data) {
|
||||||
PL_ERROR(conn, CURLE_OUT_OF_MEMORY);
|
PL_ERROR(conn, CURLE_OUT_OF_MEMORY);
|
||||||
return bufflen;
|
return CURL_WRITEFUNC_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
parser->file_data->b_size = FTP_BUFFER_ALLOCSIZE;
|
parser->file_data->b_size = FTP_BUFFER_ALLOCSIZE;
|
||||||
parser->item_offset = 0;
|
parser->item_offset = 0;
|
||||||
@ -416,7 +425,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
|
|||||||
parser->file_data = NULL;
|
parser->file_data = NULL;
|
||||||
parser->error = CURLE_OUT_OF_MEMORY;
|
parser->error = CURLE_OUT_OF_MEMORY;
|
||||||
PL_ERROR(conn, CURLE_OUT_OF_MEMORY);
|
PL_ERROR(conn, CURLE_OUT_OF_MEMORY);
|
||||||
return bufflen;
|
return CURL_WRITEFUNC_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -725,6 +725,11 @@ CURLcode rtp_client_write(struct connectdata *conn, char *ptr, size_t len)
|
|||||||
writeit = data->set.fwrite_rtp?data->set.fwrite_rtp:data->set.fwrite_func;
|
writeit = data->set.fwrite_rtp?data->set.fwrite_rtp:data->set.fwrite_func;
|
||||||
wrote = writeit(ptr, 1, len, data->set.rtp_out);
|
wrote = writeit(ptr, 1, len, data->set.rtp_out);
|
||||||
|
|
||||||
|
if(CURL_WRITEFUNC_OUT_OF_MEMORY == wrote) {
|
||||||
|
failf (data, "Out of memory writing RTP data");
|
||||||
|
return CURLE_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
if(CURL_WRITEFUNC_PAUSE == wrote) {
|
if(CURL_WRITEFUNC_PAUSE == wrote) {
|
||||||
failf (data, "Cannot pause RTP");
|
failf (data, "Cannot pause RTP");
|
||||||
return CURLE_WRITE_ERROR;
|
return CURLE_WRITE_ERROR;
|
||||||
|
11
lib/sendf.c
11
lib/sendf.c
@ -459,6 +459,11 @@ CURLcode Curl_client_write(struct connectdata *conn,
|
|||||||
wrote = len;
|
wrote = len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(CURL_WRITEFUNC_OUT_OF_MEMORY == wrote) {
|
||||||
|
failf(data, "Out of memory writing body");
|
||||||
|
return CURLE_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
if(CURL_WRITEFUNC_PAUSE == wrote)
|
if(CURL_WRITEFUNC_PAUSE == wrote)
|
||||||
return pausewrite(data, type, ptr, len);
|
return pausewrite(data, type, ptr, len);
|
||||||
|
|
||||||
@ -481,6 +486,12 @@ CURLcode Curl_client_write(struct connectdata *conn,
|
|||||||
regardless of the ftp transfer mode (ASCII/Image) */
|
regardless of the ftp transfer mode (ASCII/Image) */
|
||||||
|
|
||||||
wrote = writeit(ptr, 1, len, data->set.writeheader);
|
wrote = writeit(ptr, 1, len, data->set.writeheader);
|
||||||
|
|
||||||
|
if(CURL_WRITEFUNC_OUT_OF_MEMORY == wrote) {
|
||||||
|
failf(data, "Out of memory writing header");
|
||||||
|
return CURLE_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
if(CURL_WRITEFUNC_PAUSE == wrote)
|
if(CURL_WRITEFUNC_PAUSE == wrote)
|
||||||
/* here we pass in the HEADER bit only since if this was body as well
|
/* here we pass in the HEADER bit only since if this was body as well
|
||||||
then it was passed already and clearly that didn't trigger the pause,
|
then it was passed already and clearly that didn't trigger the pause,
|
||||||
|
@ -47,6 +47,10 @@ size_t tool_header_cb(void *ptr, size_t size, size_t nmemb, void *userdata)
|
|||||||
const size_t cb = size * nmemb;
|
const size_t cb = size * nmemb;
|
||||||
const char *end = (char*)ptr + cb;
|
const char *end = (char*)ptr + cb;
|
||||||
|
|
||||||
|
if(cb >= CURL_WRITEFUNC_PAUSE)
|
||||||
|
/* CURL_WRITEFUNC_PAUSE limits input size */
|
||||||
|
return CURL_WRITEFUNC_OUT_OF_MEMORY;
|
||||||
|
|
||||||
if(cb > 20 && checkprefix("Content-disposition:", str)) {
|
if(cb > 20 && checkprefix("Content-disposition:", str)) {
|
||||||
const char *p = str + 20;
|
const char *p = str + 20;
|
||||||
|
|
||||||
@ -74,12 +78,13 @@ size_t tool_header_cb(void *ptr, size_t size, size_t nmemb, void *userdata)
|
|||||||
*/
|
*/
|
||||||
len = (ssize_t)cb - (p - str);
|
len = (ssize_t)cb - (p - str);
|
||||||
filename = parse_filename(p, len);
|
filename = parse_filename(p, len);
|
||||||
/* TODO: OOM handling - return (size_t)-1 ? */
|
|
||||||
if(filename) {
|
if(filename) {
|
||||||
outs->filename = filename;
|
outs->filename = filename;
|
||||||
outs->alloc_filename = TRUE;
|
outs->alloc_filename = TRUE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
return CURL_WRITEFUNC_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,6 +51,10 @@ size_t tool_write_cb(void *buffer, size_t sz, size_t nmemb, void *userdata)
|
|||||||
*/
|
*/
|
||||||
const size_t err_rc = (sz * nmemb) ? 0 : 1;
|
const size_t err_rc = (sz * nmemb) ? 0 : 1;
|
||||||
|
|
||||||
|
if(sz * nmemb >= CURL_WRITEFUNC_PAUSE)
|
||||||
|
/* CURL_WRITEFUNC_PAUSE limits input size */
|
||||||
|
return CURL_WRITEFUNC_OUT_OF_MEMORY;
|
||||||
|
|
||||||
if(!out->stream) {
|
if(!out->stream) {
|
||||||
out->bytes = 0; /* nothing written yet */
|
out->bytes = 0; /* nothing written yet */
|
||||||
if(!out->filename) {
|
if(!out->filename) {
|
||||||
|
Loading…
Reference in New Issue
Block a user