Browse Source

curl.h: add CURLE_TOO_LARGE

A new error code to be used when an internal field grows too large, like
when a dynbuf reaches its maximum. Previously it would return
CURLE_OUT_OF_MEMORY for this, which is highly misleading.

Ref: #12268
Closes #12269
Daniel Stenberg 4 months ago
parent
commit
f58e493e44

+ 4 - 0
docs/libcurl/libcurl-errors.3

@@ -288,6 +288,8 @@ the specific problem.
 SSL Client Certificate required.
 .IP "CURLE_UNRECOVERABLE_POLL (99)"
 An internal call to poll() or select() returned error that is not recoverable.
+.IP "CURLE_TOO_LARGE (100)"
+A value or data field grew larger than allowed.
 .SH "CURLMcode"
 This is the generic return code used by functions in the libcurl multi
 interface. Also consider \fIcurl_multi_strerror(3)\fP.
@@ -410,6 +412,8 @@ The URL contained an invalid number of slashes.
 The user part of the URL contained bad or invalid characters.
 .IP "CURLUE_LACKS_IDN (30)"
 libcurl lacks IDN support.
+.IP "CURLUE_TOO_LARGE (31)"
+A value or data field is larger than allowed.
 .SH "CURLHcode"
 The header interface returns a \fICURLHcode\fP to indicate when an error has
 occurred.

+ 2 - 0
docs/libcurl/symbols-in-versions

@@ -328,6 +328,7 @@ CURLE_TFTP_NOSUCHUSER           7.15.0
 CURLE_TFTP_NOTFOUND             7.15.0
 CURLE_TFTP_PERM                 7.15.0
 CURLE_TFTP_UNKNOWNID            7.15.0
+CURLE_TOO_LARGE                 8.6.0
 CURLE_TOO_MANY_REDIRECTS        7.5
 CURLE_UNKNOWN_OPTION            7.21.5
 CURLE_UNKNOWN_TELNET_OPTION     7.7           7.21.5
@@ -1094,6 +1095,7 @@ CURLUE_NO_USER                  7.62.0
 CURLUE_NO_ZONEID                7.81.0
 CURLUE_OK                       7.62.0
 CURLUE_OUT_OF_MEMORY            7.62.0
+CURLUE_TOO_LARGE                8.6.0
 CURLUE_UNKNOWN_PART             7.62.0
 CURLUE_UNSUPPORTED_SCHEME       7.62.0
 CURLUE_URLDECODE                7.62.0

+ 1 - 0
include/curl/curl.h

@@ -631,6 +631,7 @@ typedef enum {
   CURLE_PROXY,                   /* 97 - proxy handshake error */
   CURLE_SSL_CLIENTCERT,          /* 98 - client-side certificate required */
   CURLE_UNRECOVERABLE_POLL,      /* 99 - poll/select returned fatal error */
+  CURLE_TOO_LARGE,               /* 100 - a value/data met its maximum */
   CURL_LAST /* never use! */
 } CURLcode;
 

+ 1 - 0
include/curl/urlapi.h

@@ -63,6 +63,7 @@ typedef enum {
   CURLUE_BAD_SLASHES,         /* 28 */
   CURLUE_BAD_USER,            /* 29 */
   CURLUE_LACKS_IDN,           /* 30 */
+  CURLUE_TOO_LARGE,           /* 31 */
   CURLUE_LAST
 } CURLUcode;
 

+ 1 - 1
lib/c-hyper.c

@@ -148,7 +148,7 @@ static int hyper_each_header(void *userdata,
 
   if(name_len + value_len + 2 > CURL_MAX_HTTP_HEADER) {
     failf(data, "Too long response header");
-    data->state.hresult = CURLE_OUT_OF_MEMORY;
+    data->state.hresult = CURLE_TOO_LARGE;
     return HYPER_ITER_BREAK;
   }
 

+ 4 - 0
lib/curl_printf.h

@@ -31,6 +31,10 @@
 
 #include <curl/mprintf.h>
 
+#define MERR_OK        0
+#define MERR_MEM       1
+#define MERR_TOO_LARGE 2
+
 # undef printf
 # undef fprintf
 # undef msnprintf

+ 5 - 2
lib/dynbuf.c

@@ -81,7 +81,7 @@ static CURLcode dyn_nappend(struct dynbuf *s,
 
   if(fit > s->toobig) {
     Curl_dyn_free(s);
-    return CURLE_OUT_OF_MEMORY;
+    return CURLE_TOO_LARGE;
   }
   else if(!a) {
     DEBUGASSERT(!indx);
@@ -199,6 +199,9 @@ CURLcode Curl_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap)
 
   if(!rc)
     return CURLE_OK;
+  else if(rc == MERR_TOO_LARGE)
+    return CURLE_TOO_LARGE;
+  return CURLE_OUT_OF_MEMORY;
 #else
   char *str;
 #ifdef __clang__
@@ -217,8 +220,8 @@ CURLcode Curl_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap)
   }
   /* If we failed, we cleanup the whole buffer and return error */
   Curl_dyn_free(s);
+  return CURLE_OK;
 #endif
-  return CURLE_OUT_OF_MEMORY;
 }
 
 /*

+ 15 - 12
lib/http.c

@@ -3179,7 +3179,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
       ) {
       result = Curl_http2_switch(data, conn, FIRSTSOCKET);
       if(result)
-        return result;
+        goto fail;
     }
     else
 #endif
@@ -3194,7 +3194,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
       DEBUGF(infof(data, "HTTP/2 over clean TCP"));
       result = Curl_http2_switch(data, conn, FIRSTSOCKET);
       if(result)
-        return result;
+        goto fail;
     }
     break;
   }
@@ -3204,11 +3204,11 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
 
   result = Curl_http_host(data, conn);
   if(result)
-    return result;
+    goto fail;
 
   result = Curl_http_useragent(data);
   if(result)
-    return result;
+    goto fail;
 
   Curl_http_method(data, conn, &request, &httpreq);
 
@@ -3224,7 +3224,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
                                    (pq ? pq : data->state.up.path), FALSE);
     free(pq);
     if(result)
-      return result;
+      goto fail;
   }
 
   Curl_safefree(data->state.aptr.ref);
@@ -3249,23 +3249,23 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
   /* we only consider transfer-encoding magic if libz support is built-in */
   result = Curl_transferencode(data);
   if(result)
-    return result;
+    goto fail;
 #endif
 
   result = Curl_http_body(data, conn, httpreq, &te);
   if(result)
-    return result;
+    goto fail;
 
   p_accept = Curl_checkheaders(data,
                                STRCONST("Accept"))?NULL:"Accept: */*\r\n";
 
   result = Curl_http_resume(data, conn, httpreq);
   if(result)
-    return result;
+    goto fail;
 
   result = Curl_http_range(data, httpreq);
   if(result)
-    return result;
+    goto fail;
 
   httpstring = get_http_string(data, conn);
 
@@ -3283,7 +3283,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
     result = Curl_http_target(data, conn, &req);
   if(result) {
     Curl_dyn_free(&req);
-    return result;
+    goto fail;
   }
 
 #ifndef CURL_DISABLE_ALTSVC
@@ -3354,7 +3354,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
 
   if(result) {
     Curl_dyn_free(&req);
-    return result;
+    goto fail;
   }
 
   if(!(conn->handler->flags&PROTOPT_SSL) &&
@@ -3390,7 +3390,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
   }
   if(result) {
     Curl_dyn_free(&req);
-    return result;
+    goto fail;
   }
 
   if((http->postsize > -1) &&
@@ -3426,6 +3426,9 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
        but is disabled here again to avoid that the chunked encoded version is
        actually used when sending the request body over h2 */
     data->req.upload_chunky = FALSE;
+fail:
+  if(CURLE_TOO_LARGE == result)
+    failf(data, "HTTP request too large");
   return result;
 }
 

+ 12 - 10
lib/mprintf.c

@@ -39,6 +39,7 @@
 
 #include "curl_setup.h"
 #include "dynbuf.h"
+#include "curl_printf.h"
 #include <curl/mprintf.h>
 
 #include "curl_memory.h"
@@ -169,8 +170,7 @@ struct nsprintf {
 
 struct asprintf {
   struct dynbuf *b;
-  bool fail; /* if an alloc has failed and thus the output is not the complete
-                data */
+  char merr;
 };
 
 static long dprintf_DollarString(char *input, char **end)
@@ -1062,25 +1062,27 @@ static int alloc_addbyter(int output, FILE *data)
 {
   struct asprintf *infop = (struct asprintf *)data;
   unsigned char outc = (unsigned char)output;
+  CURLcode result;
 
-  if(Curl_dyn_addn(infop->b, &outc, 1)) {
-    infop->fail = 1;
+  result = Curl_dyn_addn(infop->b, &outc, 1);
+  if(result) {
+    infop->merr = result == CURLE_TOO_LARGE ? MERR_TOO_LARGE : MERR_MEM;
     return -1; /* fail */
   }
   return outc; /* fputc() returns like this on success */
 }
 
-/* appends the formatted string, returns 0 on success, 1 on error */
+/* appends the formatted string, returns MERR error code */
 int Curl_dyn_vprintf(struct dynbuf *dyn, const char *format, va_list ap_save)
 {
   struct asprintf info;
   info.b = dyn;
-  info.fail = 0;
+  info.merr = MERR_OK;
 
   (void)dprintf_formatf(&info, alloc_addbyter, format, ap_save);
-  if(info.fail) {
+  if(info.merr) {
     Curl_dyn_free(info.b);
-    return 1;
+    return info.merr;
   }
   return 0;
 }
@@ -1091,10 +1093,10 @@ char *curl_mvaprintf(const char *format, va_list ap_save)
   struct dynbuf dyn;
   info.b = &dyn;
   Curl_dyn_init(info.b, DYN_APRINTF);
-  info.fail = 0;
+  info.merr = MERR_OK;
 
   (void)dprintf_formatf(&info, alloc_addbyter, format, ap_save);
-  if(info.fail) {
+  if(info.merr) {
     Curl_dyn_free(info.b);
     return NULL;
   }

+ 6 - 0
lib/strerror.c

@@ -319,6 +319,9 @@ curl_easy_strerror(CURLcode error)
   case CURLE_UNRECOVERABLE_POLL:
     return "Unrecoverable error in select/poll";
 
+  case CURLE_TOO_LARGE:
+    return "A value or data field grew larger than allowed";
+
     /* error codes not used by current libcurl */
   case CURLE_OBSOLETE20:
   case CURLE_OBSOLETE24:
@@ -553,6 +556,9 @@ curl_url_strerror(CURLUcode error)
   case CURLUE_LACKS_IDN:
     return "libcurl lacks IDN support";
 
+  case CURLUE_TOO_LARGE:
+    return "A value or data field is larger than allowed";
+
   case CURLUE_LAST:
     break;
   }

+ 75 - 62
lib/urlapi.c

@@ -126,6 +126,9 @@ static const char *find_host_sep(const char *url)
   return sep < query ? sep : query;
 }
 
+/* convert CURLcode to CURLUcode */
+#define cc2cu(x) ((x) == CURLE_TOO_LARGE ? CURLUE_TOO_LARGE :   \
+                  CURLUE_OUT_OF_MEMORY)
 /*
  * Decide whether a character in a URL must be escaped.
  */
@@ -146,6 +149,7 @@ static CURLUcode urlencode_str(struct dynbuf *o, const char *url,
   bool left = !query;
   const unsigned char *iptr;
   const unsigned char *host_sep = (const unsigned char *) url;
+  CURLcode result;
 
   if(!relative)
     host_sep = (const unsigned char *) find_host_sep(url);
@@ -154,20 +158,19 @@ static CURLUcode urlencode_str(struct dynbuf *o, const char *url,
       len; iptr++, len--) {
 
     if(iptr < host_sep) {
-      if(Curl_dyn_addn(o, iptr, 1))
-        return CURLUE_OUT_OF_MEMORY;
+      result = Curl_dyn_addn(o, iptr, 1);
+      if(result)
+        return cc2cu(result);
       continue;
     }
 
     if(*iptr == ' ') {
-      if(left) {
-        if(Curl_dyn_addn(o, "%20", 3))
-          return CURLUE_OUT_OF_MEMORY;
-      }
-      else {
-        if(Curl_dyn_addn(o, "+", 1))
-          return CURLUE_OUT_OF_MEMORY;
-      }
+      if(left)
+        result = Curl_dyn_addn(o, "%20", 3);
+      else
+        result = Curl_dyn_addn(o, "+", 1);
+      if(result)
+        return cc2cu(result);
       continue;
     }
 
@@ -178,13 +181,12 @@ static CURLUcode urlencode_str(struct dynbuf *o, const char *url,
       char out[3]={'%'};
       out[1] = hexdigits[*iptr>>4];
       out[2] = hexdigits[*iptr & 0xf];
-      if(Curl_dyn_addn(o, out, 3))
-        return CURLUE_OUT_OF_MEMORY;
-    }
-    else {
-      if(Curl_dyn_addn(o, iptr, 1))
-        return CURLUE_OUT_OF_MEMORY;
+      result = Curl_dyn_addn(o, out, 3);
     }
+    else
+      result = Curl_dyn_addn(o, iptr, 1);
+    if(result)
+      return cc2cu(result);
   }
 
   return CURLUE_OK;
@@ -248,7 +250,7 @@ size_t Curl_is_absolute_url(const char *url, char *buf, size_t buflen,
  *
  * Note that this function destroys the 'base' string.
  */
-static char *concat_url(char *base, const char *relurl)
+static CURLcode concat_url(char *base, const char *relurl, char **newurl)
 {
   /***
    TRY to append this new path to the old URL
@@ -260,6 +262,9 @@ static char *concat_url(char *base, const char *relurl)
   char *pathsep;
   bool host_changed = FALSE;
   const char *useurl = relurl;
+  CURLcode result = CURLE_OK;
+  CURLUcode uc;
+  *newurl = NULL;
 
   /* protsep points to the start of the host name */
   protsep = strstr(base, "//");
@@ -360,21 +365,27 @@ static char *concat_url(char *base, const char *relurl)
   Curl_dyn_init(&newest, CURL_MAX_INPUT_LENGTH);
 
   /* copy over the root url part */
-  if(Curl_dyn_add(&newest, base))
-    return NULL;
+  result = Curl_dyn_add(&newest, base);
+  if(result)
+    return result;
 
   /* check if we need to append a slash */
   if(('/' == useurl[0]) || (protsep && !*protsep) || ('?' == useurl[0]))
     ;
   else {
-    if(Curl_dyn_addn(&newest, "/", 1))
-      return NULL;
+    result = Curl_dyn_addn(&newest, "/", 1);
+    if(result)
+      return result;
   }
 
   /* then append the new piece on the right side */
-  urlencode_str(&newest, useurl, strlen(useurl), !host_changed, FALSE);
+  uc = urlencode_str(&newest, useurl, strlen(useurl), !host_changed,
+                     FALSE);
+  if(uc)
+    return (uc == CURLUE_TOO_LARGE) ? CURLE_TOO_LARGE : CURLE_OUT_OF_MEMORY;
 
-  return Curl_dyn_ptr(&newest);
+  *newurl = Curl_dyn_ptr(&newest);
+  return CURLE_OK;
 }
 
 /* scan for byte values <= 31, 127 and sometimes space */
@@ -775,7 +786,7 @@ static CURLUcode urldecode_host(struct dynbuf *host)
     result = Curl_dyn_addn(host, decoded, dlen);
     free(decoded);
     if(result)
-      return CURLUE_OUT_OF_MEMORY;
+      return cc2cu(result);
   }
 
   return CURLUE_OK;
@@ -788,22 +799,24 @@ static CURLUcode parse_authority(struct Curl_URL *u,
                                  bool has_scheme)
 {
   size_t offset;
-  CURLUcode result;
+  CURLUcode uc;
+  CURLcode result;
 
   /*
    * Parse the login details and strip them out of the host name.
    */
-  result = parse_hostname_login(u, auth, authlen, flags, &offset);
-  if(result)
+  uc = parse_hostname_login(u, auth, authlen, flags, &offset);
+  if(uc)
     goto out;
 
-  if(Curl_dyn_addn(host, auth + offset, authlen - offset)) {
-    result = CURLUE_OUT_OF_MEMORY;
+  result = Curl_dyn_addn(host, auth + offset, authlen - offset);
+  if(result) {
+    uc = cc2cu(result);
     goto out;
   }
 
-  result = Curl_parse_port(u, host, has_scheme);
-  if(result)
+  uc = Curl_parse_port(u, host, has_scheme);
+  if(uc)
     goto out;
 
   if(!Curl_dyn_len(host))
@@ -813,24 +826,24 @@ static CURLUcode parse_authority(struct Curl_URL *u,
   case HOST_IPV4:
     break;
   case HOST_IPV6:
-    result = ipv6_parse(u, Curl_dyn_ptr(host), Curl_dyn_len(host));
+    uc = ipv6_parse(u, Curl_dyn_ptr(host), Curl_dyn_len(host));
     break;
   case HOST_NAME:
-    result = urldecode_host(host);
-    if(!result)
-      result = hostname_check(u, Curl_dyn_ptr(host), Curl_dyn_len(host));
+    uc = urldecode_host(host);
+    if(!uc)
+      uc = hostname_check(u, Curl_dyn_ptr(host), Curl_dyn_len(host));
     break;
   case HOST_ERROR:
-    result = CURLUE_OUT_OF_MEMORY;
+    uc = CURLUE_OUT_OF_MEMORY;
     break;
   case HOST_BAD:
   default:
-    result = CURLUE_BAD_HOSTNAME; /* Bad IPv4 address even */
+    uc = CURLUE_BAD_HOSTNAME; /* Bad IPv4 address even */
     break;
   }
 
 out:
-  return result;
+  return uc;
 }
 
 CURLUcode Curl_url_set_authority(CURLU *u, const char *authority,
@@ -1079,8 +1092,9 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
 
           len = path - ptr;
           if(len) {
-            if(Curl_dyn_addn(&host, ptr, len)) {
-              result = CURLUE_OUT_OF_MEMORY;
+            CURLcode code = Curl_dyn_addn(&host, ptr, len);
+            if(code) {
+              result = cc2cu(code);
               goto fail;
             }
             uncpath = TRUE;
@@ -1233,10 +1247,9 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
       if(flags & CURLU_URLENCODE) {
         struct dynbuf enc;
         Curl_dyn_init(&enc, CURL_MAX_INPUT_LENGTH);
-        if(urlencode_str(&enc, fragment + 1, fraglen - 1, TRUE, FALSE)) {
-          result = CURLUE_OUT_OF_MEMORY;
+        result = urlencode_str(&enc, fragment + 1, fraglen - 1, TRUE, FALSE);
+        if(result)
           goto fail;
-        }
         u->fragment = Curl_dyn_ptr(&enc);
       }
       else {
@@ -1262,10 +1275,9 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
         struct dynbuf enc;
         Curl_dyn_init(&enc, CURL_MAX_INPUT_LENGTH);
         /* skip the leading question mark */
-        if(urlencode_str(&enc, query + 1, qlen - 1, TRUE, TRUE)) {
-          result = CURLUE_OUT_OF_MEMORY;
+        result = urlencode_str(&enc, query + 1, qlen - 1, TRUE, TRUE);
+        if(result)
           goto fail;
-        }
         u->query = Curl_dyn_ptr(&enc);
       }
       else {
@@ -1289,10 +1301,9 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
   if(pathlen && (flags & CURLU_URLENCODE)) {
     struct dynbuf enc;
     Curl_dyn_init(&enc, CURL_MAX_INPUT_LENGTH);
-    if(urlencode_str(&enc, path, pathlen, TRUE, FALSE)) {
-      result = CURLUE_OUT_OF_MEMORY;
+    result = urlencode_str(&enc, path, pathlen, TRUE, FALSE);
+    if(result)
       goto fail;
-    }
     pathlen = Curl_dyn_len(&enc);
     path = u->path = Curl_dyn_ptr(&enc);
   }
@@ -1628,10 +1639,11 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what,
     }
     if(urlencode) {
       struct dynbuf enc;
+      CURLUcode uc;
       Curl_dyn_init(&enc, CURL_MAX_INPUT_LENGTH);
-      if(urlencode_str(&enc, *part, partlen, TRUE,
-                       what == CURLUPART_QUERY))
-        return CURLUE_OUT_OF_MEMORY;
+      uc = urlencode_str(&enc, *part, partlen, TRUE, what == CURLUPART_QUERY);
+      if(uc)
+        return uc;
       free(*part);
       *part = Curl_dyn_ptr(&enc);
     }
@@ -1816,7 +1828,8 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
      * If the existing contents is enough for a URL, allow a relative URL to
      * replace it.
      */
-    CURLUcode result;
+    CURLcode result;
+    CURLUcode uc;
     char *oldurl;
     char *redired_url;
 
@@ -1836,14 +1849,14 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
 
     /* apply the relative part to create a new URL
      * and replace the existing one with it. */
-    redired_url = concat_url(oldurl, part);
+    result = concat_url(oldurl, part, &redired_url);
     free(oldurl);
-    if(!redired_url)
-      return CURLUE_OUT_OF_MEMORY;
+    if(result)
+      return cc2cu(result);
 
-    result = parseurl_and_replace(redired_url, u, flags);
+    uc = parseurl_and_replace(redired_url, u, flags);
     free(redired_url);
-    return result;
+    return uc;
   }
   default:
     return CURLUE_UNKNOWN_PART;
@@ -1857,7 +1870,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
     if(leadingslash && (part[0] != '/')) {
       CURLcode result = Curl_dyn_addn(&enc, "/", 1);
       if(result)
-        return CURLUE_OUT_OF_MEMORY;
+        return cc2cu(result);
     }
     if(urlencode) {
       const unsigned char *i;
@@ -1877,7 +1890,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
             equalsencode = FALSE;
           result = Curl_dyn_addn(&enc, i, 1);
           if(result)
-            return CURLUE_OUT_OF_MEMORY;
+            return cc2cu(result);
         }
         else {
           char out[3]={'%'};
@@ -1885,7 +1898,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
           out[2] = hexdigits[*i & 0xf];
           result = Curl_dyn_addn(&enc, out, 3);
           if(result)
-            return CURLUE_OUT_OF_MEMORY;
+            return cc2cu(result);
         }
       }
     }
@@ -1893,7 +1906,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
       char *p;
       CURLcode result = Curl_dyn_add(&enc, part);
       if(result)
-        return CURLUE_OUT_OF_MEMORY;
+        return cc2cu(result);
       p = Curl_dyn_ptr(&enc);
       while(*p) {
         /* make sure percent encoded are lower case */

+ 2 - 2
tests/data/test1154

@@ -47,9 +47,9 @@ User-Agent: curl/%VERSION
 Accept: */*
 
 </protocol>
-# 27 == CURLE_OUT_OF_MEMORY
+# 100 == CURLE_TOO_LARGE
 <errorcode>
-27
+100
 </errorcode>
 </verify>
 </testcase>

+ 4 - 2
tests/data/test1538

@@ -132,7 +132,8 @@ e96: QUIC connection error
 e97: proxy handshake error
 e98: SSL Client Certificate required
 e99: Unrecoverable error in select/poll
-e100: Unknown error
+e100: A value or data field grew larger than allowed
+e101: Unknown error
 m-1: Please call curl_multi_perform() soon
 m0: No error
 m1: Invalid multi handle
@@ -186,7 +187,8 @@ u27: Bad scheme
 u28: Unsupported number of slashes following scheme
 u29: Bad user
 u30: libcurl lacks IDN support
-u31: CURLUcode unknown
+u31: A value or data field is larger than allowed
+u32: CURLUcode unknown
 </stdout>
 </verify>