Skip to content

Commit

Permalink
allow write callbacks to indicate OOM to libcurl
Browse files Browse the repository at this point in the history
Allow (*curl_write_callback) write callbacks to return
CURL_WRITEFUNC_OUT_OF_MEMORY to properly indicate libcurl of OOM conditions
inside the callback itself.
  • Loading branch information
yangtse committed Sep 25, 2011
1 parent e276802 commit 119f433
Show file tree
Hide file tree
Showing 8 changed files with 50 additions and 5 deletions.
5 changes: 5 additions & 0 deletions docs/libcurl/curl_easy_setopt.3
Original file line number Diff line number Diff line change
Expand Up @@ -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
\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
empty.

Expand Down
1 change: 1 addition & 0 deletions docs/libcurl/symbols-in-versions
Original file line number Diff line number Diff line change
Expand Up @@ -685,4 +685,5 @@ CURL_VERSION_SPNEGO 7.10.8
CURL_VERSION_SSL 7.10
CURL_VERSION_SSPI 7.13.2
CURL_VERSION_TLSAUTH_SRP 7.21.4
CURL_WRITEFUNC_OUT_OF_MEMORY 7.22.1
CURL_WRITEFUNC_PAUSE 7.18.0
7 changes: 6 additions & 1 deletion include/curl/curl.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,10 +187,15 @@ typedef int (*curl_progress_callback)(void *clientp,
#define CURL_MAX_HTTP_HEADER (100*1024)
#endif


/* This is a magic return code for the write callback that, when returned,
will signal libcurl to pause receiving on the current transfer. */
#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,
size_t size,
size_t nitems,
Expand Down
15 changes: 12 additions & 3 deletions lib/ftplistparser.c
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,8 @@ static CURLcode ftp_pl_insert_finfo(struct connectdata *conn,
return CURLE_OK;
}

/* Curl_ftp_parselist is a write callback function */

size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
void *connptr)
{
Expand All @@ -365,13 +367,20 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
unsigned long i = 0;
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 */
/* scenario:
* 1. call => OK..
* 2. call => OUT_OF_MEMORY (or other error)
* 3. (last) call => is skipped RIGHT HERE and the error is hadled later
* in wc_statemach()
*/
if(parser->error == CURLE_OUT_OF_MEMORY)
return CURL_WRITEFUNC_OUT_OF_MEMORY;

return bufflen;
}

Expand All @@ -388,12 +397,12 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
parser->file_data = Curl_fileinfo_alloc();
if(!parser->file_data) {
parser->error = CURLE_OUT_OF_MEMORY;
return bufflen;
return CURL_WRITEFUNC_OUT_OF_MEMORY;
}
parser->file_data->b_data = malloc(FTP_BUFFER_ALLOCSIZE);
if(!parser->file_data->b_data) {
PL_ERROR(conn, CURLE_OUT_OF_MEMORY);
return bufflen;
return CURL_WRITEFUNC_OUT_OF_MEMORY;
}
parser->file_data->b_size = FTP_BUFFER_ALLOCSIZE;
parser->item_offset = 0;
Expand All @@ -416,7 +425,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
parser->file_data = NULL;
parser->error = CURLE_OUT_OF_MEMORY;
PL_ERROR(conn, CURLE_OUT_OF_MEMORY);
return bufflen;
return CURL_WRITEFUNC_OUT_OF_MEMORY;
}
}

Expand Down
5 changes: 5 additions & 0 deletions lib/rtsp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
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) {
failf (data, "Cannot pause RTP");
return CURLE_WRITE_ERROR;
Expand Down
11 changes: 11 additions & 0 deletions lib/sendf.c
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,11 @@ CURLcode Curl_client_write(struct connectdata *conn,
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)
return pausewrite(data, type, ptr, len);

Expand All @@ -481,6 +486,12 @@ CURLcode Curl_client_write(struct connectdata *conn,
regardless of the ftp transfer mode (ASCII/Image) */

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)
/* 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,
Expand Down
7 changes: 6 additions & 1 deletion src/tool_cb_hdr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 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)) {
const char *p = str + 20;

Expand Down Expand Up @@ -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);
filename = parse_filename(p, len);
/* TODO: OOM handling - return (size_t)-1 ? */
if(filename) {
outs->filename = filename;
outs->alloc_filename = TRUE;
break;
}
else
return CURL_WRITEFUNC_OUT_OF_MEMORY;
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/tool_cb_wrt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

if(sz * nmemb >= CURL_WRITEFUNC_PAUSE)
/* CURL_WRITEFUNC_PAUSE limits input size */
return CURL_WRITEFUNC_OUT_OF_MEMORY;

if(!out->stream) {
out->bytes = 0; /* nothing written yet */
if(!out->filename) {
Expand Down

0 comments on commit 119f433

Please sign in to comment.