]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
lib: add CURL_WRITEFUNC_ERROR to signal write callback error
authorJay Satiro <raysatiro@yahoo.com>
Tue, 8 Nov 2022 23:49:21 +0000 (18:49 -0500)
committerJay Satiro <raysatiro@yahoo.com>
Thu, 10 Nov 2022 08:13:58 +0000 (03:13 -0500)
Prior to this change if the user wanted to signal an error from their
write callbacks they would have to use logic to return a value different
from the number of bytes (nmemb) passed to the callback. Also, the
inclination of some users has been to just return 0 to signal error,
which is incorrect as that may be the number of bytes passed to the
callback.

To remedy this the user can now return CURL_WRITEFUNC_ERROR instead.

Ref: https://github.com/curl/curl/issues/9873

Closes https://github.com/curl/curl/pull/9874

docs/libcurl/opts/CURLOPT_HEADERFUNCTION.3
docs/libcurl/opts/CURLOPT_INTERLEAVEFUNCTION.3
docs/libcurl/opts/CURLOPT_WRITEFUNCTION.3
docs/libcurl/symbols-in-versions
include/curl/curl.h
src/tool_cb_hdr.c
src/tool_cb_wrt.c

index 1aff4cf13ddd3068e44604378a04b0fa547e2a1e..33286470a24cc96e1f37803c03d91afd3e380e02 100644 (file)
@@ -51,10 +51,12 @@ the header line is null-terminated!
 The pointer named \fIuserdata\fP is the one you set with the
 \fICURLOPT_HEADERDATA(3)\fP option.
 
-This callback function must return the number of bytes actually taken care of.
-If that amount differs from the amount passed in to your function, it will signal
-an error to the library. This will cause the transfer to get aborted and the
-libcurl function in progress will return \fICURLE_WRITE_ERROR\fP.
+Your callback should return the number of bytes actually taken care of. If
+that amount differs from the amount passed to your callback function, it will
+signal an error condition to the library. This will cause the transfer to get
+aborted and the libcurl function used will return \fICURLE_WRITE_ERROR\fP.
+
+You can also abort the transfer by returning CURL_WRITEFUNC_ERROR. (7.87.0)
 
 A complete HTTP header that is passed to this function can be up to
 \fICURL_MAX_HTTP_HEADER\fP (100K) bytes and includes the final line terminator.
index 8038a2cc93155d3f4c2d86473c682ff17cd54baa..211b5055e3027c08dde5e59afb324ea086055977 100644 (file)
@@ -59,6 +59,13 @@ process any pending RTP data before marking the request as finished.
 
 The \fICURLOPT_INTERLEAVEDATA(3)\fP is passed in the \fIuserdata\fP argument in
 the callback.
+
+Your callback should return the number of bytes actually taken care of. If
+that amount differs from the amount passed to your callback function, it will
+signal an error condition to the library. This will cause the transfer to get
+aborted and the libcurl function used will return \fICURLE_WRITE_ERROR\fP.
+
+You can also abort the transfer by returning CURL_WRITEFUNC_ERROR. (7.87.0)
 .SH DEFAULT
 NULL, the interleave data is then passed to the regular write function:
 \fICURLOPT_WRITEFUNCTION(3)\fP.
index 027984c4d3fca56b7b0f09ea0e85cb0ff870a57f..fcefb9d1c74737b655c83942222adb5b1475e99f 100644 (file)
@@ -63,6 +63,8 @@ that amount differs from the amount passed to your callback function, it will
 signal an error condition to the library. This will cause the transfer to get
 aborted and the libcurl function used will return \fICURLE_WRITE_ERROR\fP.
 
+You can also abort the transfer by returning CURL_WRITEFUNC_ERROR. (7.87.0)
+
 If your callback function returns CURL_WRITEFUNC_PAUSE it will cause this
 transfer to become paused.  See \fIcurl_easy_pause(3)\fP for further details.
 
index b0e55160913448707b23f36d11a22283f06f5667..6f352b7a6d480eefddc53c904cb8757e20693db8 100644 (file)
@@ -187,6 +187,7 @@ CURL_WAIT_POLLIN                7.28.0
 CURL_WAIT_POLLOUT               7.28.0
 CURL_WAIT_POLLPRI               7.28.0
 CURL_WIN32                      7.69.0
+CURL_WRITEFUNC_ERROR            7.87.0
 CURL_WRITEFUNC_PAUSE            7.18.0
 CURL_ZERO_TERMINATED            7.56.0
 CURLALTSVC_H1                   7.64.1
index 8582d1c17aa119e4c1ca7df7d03fe4cb2a90f40b..6e569ab7573775b85d2648f7809600b217da6e7e 100644 (file)
@@ -256,6 +256,10 @@ typedef int (*curl_xferinfo_callback)(void *clientp,
    will signal libcurl to pause receiving on the current transfer. */
 #define CURL_WRITEFUNC_PAUSE 0x10000001
 
+/* This is a magic return code for the write callback that, when returned,
+   will signal an error from the callback. */
+#define CURL_WRITEFUNC_ERROR 0xFFFFFFFF
+
 typedef size_t (*curl_write_callback)(char *buffer,
                                       size_t size,
                                       size_t nitems,
index 23700de222ac3b41073f402751dce68d67f1f9d3..08ee38c3b3177833424544f8af821f16e9994310 100644 (file)
@@ -77,22 +77,14 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata)
   const char *end = (char *)ptr + cb;
   const char *scheme = NULL;
 
-  /*
-   * Once that libcurl has called back tool_header_cb() the returned value
-   * is checked against the amount that was intended to be written, if
-   * it does not match then it fails with CURLE_WRITE_ERROR. So at this
-   * point returning a value different from sz*nmemb indicates failure.
-   */
-  size_t failure = (size && nmemb) ? 0 : 1;
-
   if(!per->config)
-    return failure;
+    return CURL_WRITEFUNC_ERROR;
 
 #ifdef DEBUGBUILD
   if(size * nmemb > (size_t)CURL_MAX_HTTP_HEADER) {
     warnf(per->config->global, "Header data exceeds single call write "
           "limit!\n");
-    return failure;
+    return CURL_WRITEFUNC_ERROR;
   }
 #endif
 
@@ -175,7 +167,7 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata)
         if(outs->stream) {
           /* indication of problem, get out! */
           free(filename);
-          return failure;
+          return CURL_WRITEFUNC_ERROR;
         }
 
         outs->is_cd_filename = TRUE;
@@ -185,12 +177,12 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata)
         outs->alloc_filename = TRUE;
         hdrcbdata->honor_cd_filename = FALSE; /* done now! */
         if(!tool_create_output_file(outs, per->config))
-          return failure;
+          return CURL_WRITEFUNC_ERROR;
       }
       break;
     }
     if(!outs->stream && !tool_create_output_file(outs, per->config))
-      return failure;
+      return CURL_WRITEFUNC_ERROR;
   }
   if(hdrcbdata->config->writeout) {
     char *value = memchr(ptr, ':', cb);
@@ -210,7 +202,7 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata)
     char *value = NULL;
 
     if(!outs->stream && !tool_create_output_file(outs, per->config))
-      return failure;
+      return CURL_WRITEFUNC_ERROR;
 
     if(hdrcbdata->global->isatty && hdrcbdata->global->styled_output)
       value = memchr(ptr, ':', cb);
index c9d1dbd1d2809e2930a9eb90a886bc16f24f19f2..fa8c8041856f44fa5ff934ee19014de081fe328e 100644 (file)
@@ -164,14 +164,6 @@ size_t tool_write_cb(char *buffer, size_t sz, size_t nmemb, void *userdata)
   intptr_t fhnd;
 #endif
 
-  /*
-   * Once that libcurl has called back tool_write_cb() the returned value
-   * is checked against the amount that was intended to be written, if
-   * it does not match then it fails with CURLE_WRITE_ERROR. So at this
-   * point returning a value different from sz*nmemb indicates failure.
-   */
-  const size_t failure = bytes ? 0 : 1;
-
 #ifdef DEBUGBUILD
   {
     char *tty = curlx_getenv("CURL_ISATTY");
@@ -185,13 +177,13 @@ size_t tool_write_cb(char *buffer, size_t sz, size_t nmemb, void *userdata)
     if(bytes > (size_t)CURL_MAX_HTTP_HEADER) {
       warnf(config->global, "Header data size exceeds single call write "
             "limit!\n");
-      return failure;
+      return CURL_WRITEFUNC_ERROR;
     }
   }
   else {
     if(bytes > (size_t)CURL_MAX_WRITE_SIZE) {
       warnf(config->global, "Data size exceeds single call write limit!\n");
-      return failure;
+      return CURL_WRITEFUNC_ERROR;
     }
   }
 
@@ -220,13 +212,13 @@ size_t tool_write_cb(char *buffer, size_t sz, size_t nmemb, void *userdata)
     }
     if(check_fails) {
       warnf(config->global, "Invalid output struct data for write callback\n");
-      return failure;
+      return CURL_WRITEFUNC_ERROR;
     }
   }
 #endif
 
   if(!outs->stream && !tool_create_output_file(outs, per->config))
-    return failure;
+    return CURL_WRITEFUNC_ERROR;
 
   if(is_tty && (outs->bytes < 2000) && !config->terminal_binary_ok) {
     /* binary output to terminal? */
@@ -235,7 +227,7 @@ size_t tool_write_cb(char *buffer, size_t sz, size_t nmemb, void *userdata)
             "Use \"--output -\" to tell curl to output it to your terminal "
             "anyway, or consider \"--output <FILE>\" to save to a file.\n");
       config->synthetic_error = TRUE;
-      return failure;
+      return CURL_WRITEFUNC_ERROR;
     }
   }
 
@@ -251,13 +243,13 @@ size_t tool_write_cb(char *buffer, size_t sz, size_t nmemb, void *userdata)
     wc_len = MultiByteToWideChar(CP_UTF8, 0, buffer, in_len,  NULL, 0);
     wc_buf = (wchar_t*) malloc(wc_len * sizeof(wchar_t));
     if(!wc_buf)
-      return failure;
+      return CURL_WRITEFUNC_ERROR;
 
     /* calculate buffer size for multi-byte characters */
     wc_len = MultiByteToWideChar(CP_UTF8, 0, buffer, in_len, wc_buf, wc_len);
     if(!wc_len) {
       free(wc_buf);
-      return failure;
+      return CURL_WRITEFUNC_ERROR;
     }
 
     if(!WriteConsoleW(
@@ -267,7 +259,7 @@ size_t tool_write_cb(char *buffer, size_t sz, size_t nmemb, void *userdata)
         &wc_len,
         NULL)) {
       free(wc_buf);
-      return failure;
+      return CURL_WRITEFUNC_ERROR;
     }
     free(wc_buf);
     rc = bytes;
@@ -289,7 +281,7 @@ size_t tool_write_cb(char *buffer, size_t sz, size_t nmemb, void *userdata)
     /* output buffering disabled */
     int res = fflush(outs->stream);
     if(res)
-      return failure;
+      return CURL_WRITEFUNC_ERROR;
   }
 
   return rc;