quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

easy.c (36744B)


      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
      9  *
     10  * This software is licensed as described in the file COPYING, which
     11  * you should have received as part of this distribution. The terms
     12  * are also available at https://curl.se/docs/copyright.html.
     13  *
     14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
     15  * copies of the Software, and permit persons to whom the Software is
     16  * furnished to do so, under the terms of the COPYING file.
     17  *
     18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
     19  * KIND, either express or implied.
     20  *
     21  * SPDX-License-Identifier: curl
     22  *
     23  ***************************************************************************/
     24 
     25 #include "curl_setup.h"
     26 
     27 #ifdef HAVE_NETINET_IN_H
     28 #include <netinet/in.h>
     29 #endif
     30 #ifdef HAVE_NETDB_H
     31 #include <netdb.h>
     32 #endif
     33 #ifdef HAVE_ARPA_INET_H
     34 #include <arpa/inet.h>
     35 #endif
     36 #ifdef HAVE_NET_IF_H
     37 #include <net/if.h>
     38 #endif
     39 #ifdef HAVE_SYS_IOCTL_H
     40 #include <sys/ioctl.h>
     41 #endif
     42 
     43 #ifdef HAVE_SYS_PARAM_H
     44 #include <sys/param.h>
     45 #endif
     46 
     47 #include "urldata.h"
     48 #include <curl/curl.h>
     49 #include "transfer.h"
     50 #include "vtls/vtls.h"
     51 #include "vtls/vtls_scache.h"
     52 #include "vquic/vquic.h"
     53 #include "url.h"
     54 #include "getinfo.h"
     55 #include "hostip.h"
     56 #include "share.h"
     57 #include "strdup.h"
     58 #include "progress.h"
     59 #include "easyif.h"
     60 #include "multiif.h"
     61 #include "select.h"
     62 #include "cfilters.h"
     63 #include "sendf.h" /* for failf function prototype */
     64 #include "connect.h" /* for Curl_getconnectinfo */
     65 #include "slist.h"
     66 #include "mime.h"
     67 #include "amigaos.h"
     68 #include "macos.h"
     69 #include "curlx/warnless.h"
     70 #include "curlx/wait.h"
     71 #include "sigpipe.h"
     72 #include "vssh/ssh.h"
     73 #include "setopt.h"
     74 #include "http_digest.h"
     75 #include "system_win32.h"
     76 #include "http2.h"
     77 #include "curlx/dynbuf.h"
     78 #include "altsvc.h"
     79 #include "hsts.h"
     80 
     81 #include "easy_lock.h"
     82 
     83 /* The last 3 #include files should be in this order */
     84 #include "curl_printf.h"
     85 #include "curl_memory.h"
     86 #include "memdebug.h"
     87 
     88 /* true globals -- for curl_global_init() and curl_global_cleanup() */
     89 static unsigned int  initialized;
     90 static long          easy_init_flags;
     91 
     92 #ifdef GLOBAL_INIT_IS_THREADSAFE
     93 
     94 static curl_simple_lock s_lock = CURL_SIMPLE_LOCK_INIT;
     95 #define global_init_lock() curl_simple_lock_lock(&s_lock)
     96 #define global_init_unlock() curl_simple_lock_unlock(&s_lock)
     97 
     98 #else
     99 
    100 #define global_init_lock()
    101 #define global_init_unlock()
    102 
    103 #endif
    104 
    105 /*
    106  * strdup (and other memory functions) is redefined in complicated
    107  * ways, but at this point it must be defined as the system-supplied strdup
    108  * so the callback pointer is initialized correctly.
    109  */
    110 #if defined(UNDER_CE)
    111 #define system_strdup _strdup
    112 #elif !defined(HAVE_STRDUP)
    113 #define system_strdup Curl_strdup
    114 #else
    115 #define system_strdup strdup
    116 #endif
    117 
    118 #if defined(_MSC_VER) && defined(_DLL)
    119 #  pragma warning(push)
    120 #  pragma warning(disable:4232) /* MSVC extension, dllimport identity */
    121 #endif
    122 
    123 /*
    124  * If a memory-using function (like curl_getenv) is used before
    125  * curl_global_init() is called, we need to have these pointers set already.
    126  */
    127 curl_malloc_callback Curl_cmalloc = (curl_malloc_callback)malloc;
    128 curl_free_callback Curl_cfree = (curl_free_callback)free;
    129 curl_realloc_callback Curl_crealloc = (curl_realloc_callback)realloc;
    130 curl_strdup_callback Curl_cstrdup = (curl_strdup_callback)system_strdup;
    131 curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc;
    132 
    133 #if defined(_MSC_VER) && defined(_DLL)
    134 #  pragma warning(pop)
    135 #endif
    136 
    137 #ifdef DEBUGBUILD
    138 static char *leakpointer;
    139 #endif
    140 
    141 /**
    142  * curl_global_init() globally initializes curl given a bitwise set of the
    143  * different features of what to initialize.
    144  */
    145 static CURLcode global_init(long flags, bool memoryfuncs)
    146 {
    147   if(initialized++)
    148     return CURLE_OK;
    149 
    150   if(memoryfuncs) {
    151     /* Setup the default memory functions here (again) */
    152     Curl_cmalloc = (curl_malloc_callback)malloc;
    153     Curl_cfree = (curl_free_callback)free;
    154     Curl_crealloc = (curl_realloc_callback)realloc;
    155     Curl_cstrdup = (curl_strdup_callback)system_strdup;
    156     Curl_ccalloc = (curl_calloc_callback)calloc;
    157   }
    158 
    159   if(Curl_trc_init()) {
    160     DEBUGF(fprintf(stderr, "Error: Curl_trc_init failed\n"));
    161     goto fail;
    162   }
    163 
    164   if(!Curl_ssl_init()) {
    165     DEBUGF(fprintf(stderr, "Error: Curl_ssl_init failed\n"));
    166     goto fail;
    167   }
    168 
    169   if(!Curl_vquic_init()) {
    170     DEBUGF(fprintf(stderr, "Error: Curl_vquic_init failed\n"));
    171     goto fail;
    172   }
    173 
    174   if(Curl_win32_init(flags)) {
    175     DEBUGF(fprintf(stderr, "Error: win32_init failed\n"));
    176     goto fail;
    177   }
    178 
    179   if(Curl_amiga_init()) {
    180     DEBUGF(fprintf(stderr, "Error: Curl_amiga_init failed\n"));
    181     goto fail;
    182   }
    183 
    184   if(Curl_macos_init()) {
    185     DEBUGF(fprintf(stderr, "Error: Curl_macos_init failed\n"));
    186     goto fail;
    187   }
    188 
    189   if(Curl_async_global_init()) {
    190     DEBUGF(fprintf(stderr, "Error: resolver_global_init failed\n"));
    191     goto fail;
    192   }
    193 
    194   if(Curl_ssh_init()) {
    195     DEBUGF(fprintf(stderr, "Error: Curl_ssh_init failed\n"));
    196     goto fail;
    197   }
    198 
    199   easy_init_flags = flags;
    200 
    201 #ifdef DEBUGBUILD
    202   if(getenv("CURL_GLOBAL_INIT"))
    203     /* alloc data that will leak if *cleanup() is not called! */
    204     leakpointer = malloc(1);
    205 #endif
    206 
    207   return CURLE_OK;
    208 
    209 fail:
    210   initialized--; /* undo the increase */
    211   return CURLE_FAILED_INIT;
    212 }
    213 
    214 
    215 /**
    216  * curl_global_init() globally initializes curl given a bitwise set of the
    217  * different features of what to initialize.
    218  */
    219 CURLcode curl_global_init(long flags)
    220 {
    221   CURLcode result;
    222   global_init_lock();
    223 
    224   result = global_init(flags, TRUE);
    225 
    226   global_init_unlock();
    227 
    228   return result;
    229 }
    230 
    231 /*
    232  * curl_global_init_mem() globally initializes curl and also registers the
    233  * user provided callback routines.
    234  */
    235 CURLcode curl_global_init_mem(long flags, curl_malloc_callback m,
    236                               curl_free_callback f, curl_realloc_callback r,
    237                               curl_strdup_callback s, curl_calloc_callback c)
    238 {
    239   CURLcode result;
    240 
    241   /* Invalid input, return immediately */
    242   if(!m || !f || !r || !s || !c)
    243     return CURLE_FAILED_INIT;
    244 
    245   global_init_lock();
    246 
    247   if(initialized) {
    248     /* Already initialized, do not do it again, but bump the variable anyway to
    249        work like curl_global_init() and require the same amount of cleanup
    250        calls. */
    251     initialized++;
    252     global_init_unlock();
    253     return CURLE_OK;
    254   }
    255 
    256   /* set memory functions before global_init() in case it wants memory
    257      functions */
    258   Curl_cmalloc = m;
    259   Curl_cfree = f;
    260   Curl_cstrdup = s;
    261   Curl_crealloc = r;
    262   Curl_ccalloc = c;
    263 
    264   /* Call the actual init function, but without setting */
    265   result = global_init(flags, FALSE);
    266 
    267   global_init_unlock();
    268 
    269   return result;
    270 }
    271 
    272 /**
    273  * curl_global_cleanup() globally cleanups curl, uses the value of
    274  * "easy_init_flags" to determine what needs to be cleaned up and what does
    275  * not.
    276  */
    277 void curl_global_cleanup(void)
    278 {
    279   global_init_lock();
    280 
    281   if(!initialized) {
    282     global_init_unlock();
    283     return;
    284   }
    285 
    286   if(--initialized) {
    287     global_init_unlock();
    288     return;
    289   }
    290 
    291   Curl_ssl_cleanup();
    292   Curl_async_global_cleanup();
    293 
    294 #ifdef _WIN32
    295   Curl_win32_cleanup(easy_init_flags);
    296 #endif
    297 
    298   Curl_amiga_cleanup();
    299 
    300   Curl_ssh_cleanup();
    301 
    302 #ifdef DEBUGBUILD
    303   free(leakpointer);
    304 #endif
    305 
    306   easy_init_flags = 0;
    307 
    308   global_init_unlock();
    309 }
    310 
    311 /**
    312  * curl_global_trace() globally initializes curl logging.
    313  */
    314 CURLcode curl_global_trace(const char *config)
    315 {
    316 #ifndef CURL_DISABLE_VERBOSE_STRINGS
    317   CURLcode result;
    318   global_init_lock();
    319 
    320   result = Curl_trc_opt(config);
    321 
    322   global_init_unlock();
    323 
    324   return result;
    325 #else
    326   (void)config;
    327   return CURLE_OK;
    328 #endif
    329 }
    330 
    331 /*
    332  * curl_global_sslset() globally initializes the SSL backend to use.
    333  */
    334 CURLsslset curl_global_sslset(curl_sslbackend id, const char *name,
    335                               const curl_ssl_backend ***avail)
    336 {
    337   CURLsslset rc;
    338 
    339   global_init_lock();
    340 
    341   rc = Curl_init_sslset_nolock(id, name, avail);
    342 
    343   global_init_unlock();
    344 
    345   return rc;
    346 }
    347 
    348 /*
    349  * curl_easy_init() is the external interface to alloc, setup and init an
    350  * easy handle that is returned. If anything goes wrong, NULL is returned.
    351  */
    352 CURL *curl_easy_init(void)
    353 {
    354   CURLcode result;
    355   struct Curl_easy *data;
    356 
    357   /* Make sure we inited the global SSL stuff */
    358   global_init_lock();
    359 
    360   if(!initialized) {
    361     result = global_init(CURL_GLOBAL_DEFAULT, TRUE);
    362     if(result) {
    363       /* something in the global init failed, return nothing */
    364       DEBUGF(fprintf(stderr, "Error: curl_global_init failed\n"));
    365       global_init_unlock();
    366       return NULL;
    367     }
    368   }
    369   global_init_unlock();
    370 
    371   /* We use curl_open() with undefined URL so far */
    372   result = Curl_open(&data);
    373   if(result) {
    374     DEBUGF(fprintf(stderr, "Error: Curl_open failed\n"));
    375     return NULL;
    376   }
    377 
    378   return data;
    379 }
    380 
    381 #ifdef DEBUGBUILD
    382 
    383 struct socketmonitor {
    384   struct socketmonitor *next; /* the next node in the list or NULL */
    385   struct pollfd socket; /* socket info of what to monitor */
    386 };
    387 
    388 struct events {
    389   long ms;              /* timeout, run the timeout function when reached */
    390   bool msbump;          /* set TRUE when timeout is set by callback */
    391   int num_sockets;      /* number of nodes in the monitor list */
    392   struct socketmonitor *list; /* list of sockets to monitor */
    393   int running_handles;  /* store the returned number */
    394 };
    395 
    396 #define DEBUG_EV_POLL   0
    397 
    398 /* events_timer
    399  *
    400  * Callback that gets called with a new value when the timeout should be
    401  * updated.
    402  */
    403 static int events_timer(CURLM *multi,    /* multi handle */
    404                         long timeout_ms, /* see above */
    405                         void *userp)     /* private callback pointer */
    406 {
    407   struct events *ev = userp;
    408   (void)multi;
    409 #if DEBUG_EV_POLL
    410   fprintf(stderr, "events_timer: set timeout %ldms\n", timeout_ms);
    411 #endif
    412   ev->ms = timeout_ms;
    413   ev->msbump = TRUE;
    414   return 0;
    415 }
    416 
    417 
    418 /* poll2cselect
    419  *
    420  * convert from poll() bit definitions to libcurl's CURL_CSELECT_* ones
    421  */
    422 static int poll2cselect(int pollmask)
    423 {
    424   int omask = 0;
    425   if(pollmask & POLLIN)
    426     omask |= CURL_CSELECT_IN;
    427   if(pollmask & POLLOUT)
    428     omask |= CURL_CSELECT_OUT;
    429   if(pollmask & POLLERR)
    430     omask |= CURL_CSELECT_ERR;
    431   return omask;
    432 }
    433 
    434 
    435 /* socketcb2poll
    436  *
    437  * convert from libcurl' CURL_POLL_* bit definitions to poll()'s
    438  */
    439 static short socketcb2poll(int pollmask)
    440 {
    441   short omask = 0;
    442   if(pollmask & CURL_POLL_IN)
    443     omask |= POLLIN;
    444   if(pollmask & CURL_POLL_OUT)
    445     omask |= POLLOUT;
    446   return omask;
    447 }
    448 
    449 /* events_socket
    450  *
    451  * Callback that gets called with information about socket activity to
    452  * monitor.
    453  */
    454 static int events_socket(CURL *easy,      /* easy handle */
    455                          curl_socket_t s, /* socket */
    456                          int what,        /* see above */
    457                          void *userp,     /* private callback
    458                                              pointer */
    459                          void *socketp)   /* private socket
    460                                              pointer */
    461 {
    462   struct events *ev = userp;
    463   struct socketmonitor *m;
    464   struct socketmonitor *prev = NULL;
    465   bool found = FALSE;
    466   struct Curl_easy *data = easy;
    467 
    468 #if defined(CURL_DISABLE_VERBOSE_STRINGS)
    469   (void) easy;
    470 #endif
    471   (void)socketp;
    472 
    473   m = ev->list;
    474   while(m) {
    475     if(m->socket.fd == s) {
    476       found = TRUE;
    477       if(what == CURL_POLL_REMOVE) {
    478         struct socketmonitor *nxt = m->next;
    479         /* remove this node from the list of monitored sockets */
    480         if(prev)
    481           prev->next = nxt;
    482         else
    483           ev->list = nxt;
    484         free(m);
    485         infof(data, "socket cb: socket %" FMT_SOCKET_T " REMOVED", s);
    486       }
    487       else {
    488         /* The socket 's' is already being monitored, update the activity
    489            mask. Convert from libcurl bitmask to the poll one. */
    490         m->socket.events = socketcb2poll(what);
    491         infof(data, "socket cb: socket %" FMT_SOCKET_T
    492               " UPDATED as %s%s", s,
    493               (what&CURL_POLL_IN) ? "IN" : "",
    494               (what&CURL_POLL_OUT) ? "OUT" : "");
    495       }
    496       break;
    497     }
    498     prev = m;
    499     m = m->next; /* move to next node */
    500   }
    501 
    502   if(!found) {
    503     if(what == CURL_POLL_REMOVE) {
    504       /* should not happen if our logic is correct, but is no drama. */
    505       DEBUGF(infof(data, "socket cb: asked to REMOVE socket %"
    506                    FMT_SOCKET_T "but not present!", s));
    507       DEBUGASSERT(0);
    508     }
    509     else {
    510       m = malloc(sizeof(struct socketmonitor));
    511       if(m) {
    512         m->next = ev->list;
    513         m->socket.fd = s;
    514         m->socket.events = socketcb2poll(what);
    515         m->socket.revents = 0;
    516         ev->list = m;
    517         infof(data, "socket cb: socket %" FMT_SOCKET_T " ADDED as %s%s", s,
    518               (what&CURL_POLL_IN) ? "IN" : "",
    519               (what&CURL_POLL_OUT) ? "OUT" : "");
    520       }
    521       else
    522         return CURLE_OUT_OF_MEMORY;
    523     }
    524   }
    525 
    526   return 0;
    527 }
    528 
    529 
    530 /*
    531  * events_setup()
    532  *
    533  * Do the multi handle setups that only event-based transfers need.
    534  */
    535 static void events_setup(struct Curl_multi *multi, struct events *ev)
    536 {
    537   /* timer callback */
    538   curl_multi_setopt(multi, CURLMOPT_TIMERFUNCTION, events_timer);
    539   curl_multi_setopt(multi, CURLMOPT_TIMERDATA, ev);
    540 
    541   /* socket callback */
    542   curl_multi_setopt(multi, CURLMOPT_SOCKETFUNCTION, events_socket);
    543   curl_multi_setopt(multi, CURLMOPT_SOCKETDATA, ev);
    544 }
    545 
    546 /* populate_fds()
    547  *
    548  * populate the fds[] array
    549  */
    550 static unsigned int populate_fds(struct pollfd *fds, struct events *ev)
    551 {
    552   unsigned int numfds = 0;
    553   struct pollfd *f;
    554   struct socketmonitor *m;
    555 
    556   f = &fds[0];
    557   for(m = ev->list; m; m = m->next) {
    558     f->fd = m->socket.fd;
    559     f->events = m->socket.events;
    560     f->revents = 0;
    561 #if DEBUG_EV_POLL
    562     fprintf(stderr, "poll() %d check socket %d\n", numfds, f->fd);
    563 #endif
    564     f++;
    565     numfds++;
    566   }
    567   return numfds;
    568 }
    569 
    570 /* wait_or_timeout()
    571  *
    572  * waits for activity on any of the given sockets, or the timeout to trigger.
    573  */
    574 static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
    575 {
    576   bool done = FALSE;
    577   CURLMcode mcode = CURLM_OK;
    578   CURLcode result = CURLE_OK;
    579 
    580   while(!done) {
    581     CURLMsg *msg;
    582     struct pollfd fds[4];
    583     int pollrc;
    584     struct curltime before;
    585     const unsigned int numfds = populate_fds(fds, ev);
    586 
    587     /* get the time stamp to use to figure out how long poll takes */
    588     before = curlx_now();
    589 
    590     if(numfds) {
    591       /* wait for activity or timeout */
    592 #if DEBUG_EV_POLL
    593       fprintf(stderr, "poll(numfds=%u, timeout=%ldms)\n", numfds, ev->ms);
    594 #endif
    595       pollrc = Curl_poll(fds, numfds, ev->ms);
    596 #if DEBUG_EV_POLL
    597       fprintf(stderr, "poll(numfds=%u, timeout=%ldms) -> %d\n",
    598               numfds, ev->ms, pollrc);
    599 #endif
    600       if(pollrc < 0)
    601         return CURLE_UNRECOVERABLE_POLL;
    602     }
    603     else {
    604 #if DEBUG_EV_POLL
    605       fprintf(stderr, "poll, but no fds, wait timeout=%ldms\n", ev->ms);
    606 #endif
    607       pollrc = 0;
    608       if(ev->ms > 0)
    609         curlx_wait_ms(ev->ms);
    610     }
    611 
    612     ev->msbump = FALSE; /* reset here */
    613 
    614     if(!pollrc) {
    615       /* timeout! */
    616       ev->ms = 0;
    617       /* fprintf(stderr, "call curl_multi_socket_action(TIMEOUT)\n"); */
    618       mcode = curl_multi_socket_action(multi, CURL_SOCKET_TIMEOUT, 0,
    619                                        &ev->running_handles);
    620     }
    621     else {
    622       /* here pollrc is > 0 */
    623       /* loop over the monitored sockets to see which ones had activity */
    624       unsigned int i;
    625       for(i = 0; i < numfds; i++) {
    626         if(fds[i].revents) {
    627           /* socket activity, tell libcurl */
    628           int act = poll2cselect(fds[i].revents); /* convert */
    629 
    630           /* sending infof "randomly" to the first easy handle */
    631           infof(multi->admin, "call curl_multi_socket_action(socket "
    632                 "%" FMT_SOCKET_T ")", (curl_socket_t)fds[i].fd);
    633           mcode = curl_multi_socket_action(multi, fds[i].fd, act,
    634                                            &ev->running_handles);
    635         }
    636       }
    637 
    638 
    639       if(!ev->msbump && ev->ms >= 0) {
    640         /* If nothing updated the timeout, we decrease it by the spent time.
    641          * If it was updated, it has the new timeout time stored already.
    642          */
    643         timediff_t timediff = curlx_timediff(curlx_now(), before);
    644         if(timediff > 0) {
    645 #if DEBUG_EV_POLL
    646         fprintf(stderr, "poll timeout %ldms not updated, decrease by "
    647                 "time spent %ldms\n", ev->ms, (long)timediff);
    648 #endif
    649           if(timediff > ev->ms)
    650             ev->ms = 0;
    651           else
    652             ev->ms -= (long)timediff;
    653         }
    654       }
    655     }
    656 
    657     if(mcode)
    658       return CURLE_URL_MALFORMAT;
    659 
    660     /* we do not really care about the "msgs_in_queue" value returned in the
    661        second argument */
    662     msg = curl_multi_info_read(multi, &pollrc);
    663     if(msg) {
    664       result = msg->data.result;
    665       done = TRUE;
    666     }
    667   }
    668 
    669   return result;
    670 }
    671 
    672 
    673 /* easy_events()
    674  *
    675  * Runs a transfer in a blocking manner using the events-based API
    676  */
    677 static CURLcode easy_events(struct Curl_multi *multi)
    678 {
    679   /* this struct is made static to allow it to be used after this function
    680      returns and curl_multi_remove_handle() is called */
    681   static struct events evs = {-1, FALSE, 0, NULL, 0};
    682 
    683   /* if running event-based, do some further multi inits */
    684   events_setup(multi, &evs);
    685 
    686   return wait_or_timeout(multi, &evs);
    687 }
    688 #else /* DEBUGBUILD */
    689 /* when not built with debug, this function does not exist */
    690 #define easy_events(x) CURLE_NOT_BUILT_IN
    691 #endif
    692 
    693 static CURLcode easy_transfer(struct Curl_multi *multi)
    694 {
    695   bool done = FALSE;
    696   CURLMcode mcode = CURLM_OK;
    697   CURLcode result = CURLE_OK;
    698 
    699   while(!done && !mcode) {
    700     int still_running = 0;
    701 
    702     mcode = curl_multi_poll(multi, NULL, 0, 1000, NULL);
    703 
    704     if(!mcode)
    705       mcode = curl_multi_perform(multi, &still_running);
    706 
    707     /* only read 'still_running' if curl_multi_perform() return OK */
    708     if(!mcode && !still_running) {
    709       int rc;
    710       CURLMsg *msg = curl_multi_info_read(multi, &rc);
    711       if(msg) {
    712         result = msg->data.result;
    713         done = TRUE;
    714       }
    715     }
    716   }
    717 
    718   /* Make sure to return some kind of error if there was a multi problem */
    719   if(mcode) {
    720     result = (mcode == CURLM_OUT_OF_MEMORY) ? CURLE_OUT_OF_MEMORY :
    721       /* The other multi errors should never happen, so return
    722          something suitably generic */
    723       CURLE_BAD_FUNCTION_ARGUMENT;
    724   }
    725 
    726   return result;
    727 }
    728 
    729 
    730 /*
    731  * easy_perform() is the internal interface that performs a blocking
    732  * transfer as previously setup.
    733  *
    734  * CONCEPT: This function creates a multi handle, adds the easy handle to it,
    735  * runs curl_multi_perform() until the transfer is done, then detaches the
    736  * easy handle, destroys the multi handle and returns the easy handle's return
    737  * code.
    738  *
    739  * REALITY: it cannot just create and destroy the multi handle that easily. It
    740  * needs to keep it around since if this easy handle is used again by this
    741  * function, the same multi handle must be reused so that the same pools and
    742  * caches can be used.
    743  *
    744  * DEBUG: if 'events' is set TRUE, this function will use a replacement engine
    745  * instead of curl_multi_perform() and use curl_multi_socket_action().
    746  */
    747 static CURLcode easy_perform(struct Curl_easy *data, bool events)
    748 {
    749   struct Curl_multi *multi;
    750   CURLMcode mcode;
    751   CURLcode result = CURLE_OK;
    752   SIGPIPE_VARIABLE(pipe_st);
    753 
    754   if(!data)
    755     return CURLE_BAD_FUNCTION_ARGUMENT;
    756 
    757   if(data->set.errorbuffer)
    758     /* clear this as early as possible */
    759     data->set.errorbuffer[0] = 0;
    760 
    761   data->state.os_errno = 0;
    762 
    763   if(data->multi) {
    764     failf(data, "easy handle already used in multi handle");
    765     return CURLE_FAILED_INIT;
    766   }
    767 
    768   /* if the handle has a connection still attached (it is/was a connect-only
    769      handle) then disconnect before performing */
    770   if(data->conn) {
    771     struct connectdata *c;
    772     curl_socket_t s;
    773     Curl_detach_connection(data);
    774     s = Curl_getconnectinfo(data, &c);
    775     if((s != CURL_SOCKET_BAD) && c) {
    776       Curl_conn_terminate(data, c, TRUE);
    777     }
    778     DEBUGASSERT(!data->conn);
    779   }
    780 
    781   if(data->multi_easy)
    782     multi = data->multi_easy;
    783   else {
    784     /* this multi handle will only ever have a single easy handle attached to
    785        it, so make it use minimal hash sizes */
    786     multi = Curl_multi_handle(16, 1, 3, 7, 3);
    787     if(!multi)
    788       return CURLE_OUT_OF_MEMORY;
    789   }
    790 
    791   if(multi->in_callback)
    792     return CURLE_RECURSIVE_API_CALL;
    793 
    794   /* Copy the MAXCONNECTS option to the multi handle */
    795   curl_multi_setopt(multi, CURLMOPT_MAXCONNECTS, (long)data->set.maxconnects);
    796 
    797   data->multi_easy = NULL; /* pretend it does not exist */
    798   mcode = curl_multi_add_handle(multi, data);
    799   if(mcode) {
    800     curl_multi_cleanup(multi);
    801     if(mcode == CURLM_OUT_OF_MEMORY)
    802       return CURLE_OUT_OF_MEMORY;
    803     return CURLE_FAILED_INIT;
    804   }
    805 
    806   /* assign this after curl_multi_add_handle() */
    807   data->multi_easy = multi;
    808 
    809   sigpipe_init(&pipe_st);
    810   sigpipe_apply(data, &pipe_st);
    811 
    812   /* run the transfer */
    813   result = events ? easy_events(multi) : easy_transfer(multi);
    814 
    815   /* ignoring the return code is not nice, but atm we cannot really handle
    816      a failure here, room for future improvement! */
    817   (void)curl_multi_remove_handle(multi, data);
    818 
    819   sigpipe_restore(&pipe_st);
    820 
    821   /* The multi handle is kept alive, owned by the easy handle */
    822   return result;
    823 }
    824 
    825 
    826 /*
    827  * curl_easy_perform() is the external interface that performs a blocking
    828  * transfer as previously setup.
    829  */
    830 CURLcode curl_easy_perform(CURL *data)
    831 {
    832   return easy_perform(data, FALSE);
    833 }
    834 
    835 #ifdef DEBUGBUILD
    836 /*
    837  * curl_easy_perform_ev() is the external interface that performs a blocking
    838  * transfer using the event-based API internally.
    839  */
    840 CURLcode curl_easy_perform_ev(struct Curl_easy *data)
    841 {
    842   return easy_perform(data, TRUE);
    843 }
    844 
    845 #endif
    846 
    847 /*
    848  * curl_easy_cleanup() is the external interface to cleaning/freeing the given
    849  * easy handle.
    850  */
    851 void curl_easy_cleanup(CURL *ptr)
    852 {
    853   struct Curl_easy *data = ptr;
    854   if(GOOD_EASY_HANDLE(data)) {
    855     SIGPIPE_VARIABLE(pipe_st);
    856     sigpipe_ignore(data, &pipe_st);
    857     Curl_close(&data);
    858     sigpipe_restore(&pipe_st);
    859   }
    860 }
    861 
    862 /*
    863  * curl_easy_getinfo() is an external interface that allows an app to retrieve
    864  * information from a performed transfer and similar.
    865  */
    866 #undef curl_easy_getinfo
    867 CURLcode curl_easy_getinfo(CURL *data, CURLINFO info, ...)
    868 {
    869   va_list arg;
    870   void *paramp;
    871   CURLcode result;
    872 
    873   va_start(arg, info);
    874   paramp = va_arg(arg, void *);
    875 
    876   result = Curl_getinfo(data, info, paramp);
    877 
    878   va_end(arg);
    879   return result;
    880 }
    881 
    882 static CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src)
    883 {
    884   CURLcode result = CURLE_OK;
    885   enum dupstring i;
    886   enum dupblob j;
    887 
    888   /* Copy src->set into dst->set first, then deal with the strings
    889      afterwards */
    890   dst->set = src->set;
    891   Curl_mime_initpart(&dst->set.mimepost);
    892 
    893   /* clear all dest string and blob pointers first, in case we error out
    894      mid-function */
    895   memset(dst->set.str, 0, STRING_LAST * sizeof(char *));
    896   memset(dst->set.blobs, 0, BLOB_LAST * sizeof(struct curl_blob *));
    897 
    898   /* duplicate all strings */
    899   for(i = (enum dupstring)0; i < STRING_LASTZEROTERMINATED; i++) {
    900     result = Curl_setstropt(&dst->set.str[i], src->set.str[i]);
    901     if(result)
    902       return result;
    903   }
    904 
    905   /* duplicate all blobs */
    906   for(j = (enum dupblob)0; j < BLOB_LAST; j++) {
    907     result = Curl_setblobopt(&dst->set.blobs[j], src->set.blobs[j]);
    908     if(result)
    909       return result;
    910   }
    911 
    912   /* duplicate memory areas pointed to */
    913   i = STRING_COPYPOSTFIELDS;
    914   if(src->set.str[i]) {
    915     if(src->set.postfieldsize == -1)
    916       dst->set.str[i] = strdup(src->set.str[i]);
    917     else
    918       /* postfieldsize is curl_off_t, Curl_memdup() takes a size_t ... */
    919       dst->set.str[i] = Curl_memdup(src->set.str[i],
    920                                     curlx_sotouz(src->set.postfieldsize));
    921     if(!dst->set.str[i])
    922       return CURLE_OUT_OF_MEMORY;
    923     /* point to the new copy */
    924     dst->set.postfields = dst->set.str[i];
    925   }
    926 
    927   /* Duplicate mime data. */
    928   result = Curl_mime_duppart(dst, &dst->set.mimepost, &src->set.mimepost);
    929 
    930   if(src->set.resolve)
    931     dst->state.resolve = dst->set.resolve;
    932 
    933   return result;
    934 }
    935 
    936 static void dupeasy_meta_freeentry(void *p)
    937 {
    938   (void)p;
    939   /* Will always be FALSE. Cannot use a 0 assert here since compilers
    940    * are not in agreement if they then want a NORETURN attribute or
    941    * not. *sigh* */
    942   DEBUGASSERT(p == NULL);
    943 }
    944 
    945 /*
    946  * curl_easy_duphandle() is an external interface to allow duplication of a
    947  * given input easy handle. The returned handle will be a new working handle
    948  * with all options set exactly as the input source handle.
    949  */
    950 CURL *curl_easy_duphandle(CURL *d)
    951 {
    952   struct Curl_easy *data = d;
    953   struct Curl_easy *outcurl = calloc(1, sizeof(struct Curl_easy));
    954   if(!outcurl)
    955     goto fail;
    956 
    957   /*
    958    * We setup a few buffers we need. We should probably make them
    959    * get setup on-demand in the code, as that would probably decrease
    960    * the likeliness of us forgetting to init a buffer here in the future.
    961    */
    962   outcurl->set.buffer_size = data->set.buffer_size;
    963 
    964   Curl_hash_init(&outcurl->meta_hash, 23,
    965                  Curl_hash_str, curlx_str_key_compare, dupeasy_meta_freeentry);
    966   curlx_dyn_init(&outcurl->state.headerb, CURL_MAX_HTTP_HEADER);
    967   Curl_netrc_init(&outcurl->state.netrc);
    968 
    969   /* the connection pool is setup on demand */
    970   outcurl->state.lastconnect_id = -1;
    971   outcurl->state.recent_conn_id = -1;
    972   outcurl->id = -1;
    973   outcurl->mid = UINT_MAX;
    974   outcurl->master_mid = UINT_MAX;
    975 
    976 #ifndef CURL_DISABLE_HTTP
    977   Curl_llist_init(&outcurl->state.httphdrs, NULL);
    978 #endif
    979   Curl_initinfo(outcurl);
    980 
    981   /* copy all userdefined values */
    982   if(dupset(outcurl, data))
    983     goto fail;
    984 
    985   outcurl->progress.hide     = data->progress.hide;
    986   outcurl->progress.callback = data->progress.callback;
    987 
    988 #ifndef CURL_DISABLE_COOKIES
    989   outcurl->state.cookielist = NULL;
    990   if(data->cookies && data->state.cookie_engine) {
    991     /* If cookies are enabled in the parent handle, we enable them
    992        in the clone as well! */
    993     outcurl->cookies = Curl_cookie_init(outcurl, NULL, outcurl->cookies,
    994                                         data->set.cookiesession);
    995     if(!outcurl->cookies)
    996       goto fail;
    997   }
    998 
    999   if(data->state.cookielist) {
   1000     outcurl->state.cookielist = Curl_slist_duplicate(data->state.cookielist);
   1001     if(!outcurl->state.cookielist)
   1002       goto fail;
   1003   }
   1004 #endif
   1005 
   1006   if(data->state.url) {
   1007     outcurl->state.url = strdup(data->state.url);
   1008     if(!outcurl->state.url)
   1009       goto fail;
   1010     outcurl->state.url_alloc = TRUE;
   1011   }
   1012 
   1013   if(data->state.referer) {
   1014     outcurl->state.referer = strdup(data->state.referer);
   1015     if(!outcurl->state.referer)
   1016       goto fail;
   1017     outcurl->state.referer_alloc = TRUE;
   1018   }
   1019 
   1020   /* Reinitialize an SSL engine for the new handle
   1021    * note: the engine name has already been copied by dupset */
   1022   if(outcurl->set.str[STRING_SSL_ENGINE]) {
   1023     if(Curl_ssl_set_engine(outcurl, outcurl->set.str[STRING_SSL_ENGINE]))
   1024       goto fail;
   1025   }
   1026 
   1027 #ifndef CURL_DISABLE_ALTSVC
   1028   if(data->asi) {
   1029     outcurl->asi = Curl_altsvc_init();
   1030     if(!outcurl->asi)
   1031       goto fail;
   1032     if(outcurl->set.str[STRING_ALTSVC])
   1033       (void)Curl_altsvc_load(outcurl->asi, outcurl->set.str[STRING_ALTSVC]);
   1034   }
   1035 #endif
   1036 #ifndef CURL_DISABLE_HSTS
   1037   if(data->hsts) {
   1038     outcurl->hsts = Curl_hsts_init();
   1039     if(!outcurl->hsts)
   1040       goto fail;
   1041     if(outcurl->set.str[STRING_HSTS])
   1042       (void)Curl_hsts_loadfile(outcurl,
   1043                                outcurl->hsts, outcurl->set.str[STRING_HSTS]);
   1044     (void)Curl_hsts_loadcb(outcurl, outcurl->hsts);
   1045   }
   1046 #endif
   1047 
   1048   outcurl->magic = CURLEASY_MAGIC_NUMBER;
   1049 
   1050   /* we reach this point and thus we are OK */
   1051 
   1052   return outcurl;
   1053 
   1054 fail:
   1055 
   1056   if(outcurl) {
   1057 #ifndef CURL_DISABLE_COOKIES
   1058     free(outcurl->cookies);
   1059 #endif
   1060     curlx_dyn_free(&outcurl->state.headerb);
   1061     Curl_altsvc_cleanup(&outcurl->asi);
   1062     Curl_hsts_cleanup(&outcurl->hsts);
   1063     Curl_freeset(outcurl);
   1064     free(outcurl);
   1065   }
   1066 
   1067   return NULL;
   1068 }
   1069 
   1070 /*
   1071  * curl_easy_reset() is an external interface that allows an app to re-
   1072  * initialize a session handle to the default values.
   1073  */
   1074 void curl_easy_reset(CURL *d)
   1075 {
   1076   struct Curl_easy *data = d;
   1077   Curl_req_hard_reset(&data->req, data);
   1078   Curl_hash_clean(&data->meta_hash);
   1079 
   1080   /* clear all meta data */
   1081   Curl_meta_reset(data);
   1082   /* clear any resolve data */
   1083   Curl_async_shutdown(data);
   1084   Curl_resolv_unlink(data, &data->state.dns[0]);
   1085   Curl_resolv_unlink(data, &data->state.dns[1]);
   1086   /* zero out UserDefined data: */
   1087   Curl_freeset(data);
   1088   memset(&data->set, 0, sizeof(struct UserDefined));
   1089   (void)Curl_init_userdefined(data);
   1090 
   1091   /* zero out Progress data: */
   1092   memset(&data->progress, 0, sizeof(struct Progress));
   1093 
   1094   /* zero out PureInfo data: */
   1095   Curl_initinfo(data);
   1096 
   1097   data->progress.hide = TRUE;
   1098   data->state.current_speed = -1; /* init to negative == impossible */
   1099   data->state.retrycount = 0;     /* reset the retry counter */
   1100 
   1101   /* zero out authentication data: */
   1102   memset(&data->state.authhost, 0, sizeof(struct auth));
   1103   memset(&data->state.authproxy, 0, sizeof(struct auth));
   1104 
   1105 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_DIGEST_AUTH)
   1106   Curl_http_auth_cleanup_digest(data);
   1107 #endif
   1108   data->master_mid = UINT_MAX;
   1109 }
   1110 
   1111 /*
   1112  * curl_easy_pause() allows an application to pause or unpause a specific
   1113  * transfer and direction. This function sets the full new state for the
   1114  * current connection this easy handle operates on.
   1115  *
   1116  * NOTE: if you have the receiving paused and you call this function to remove
   1117  * the pausing, you may get your write callback called at this point.
   1118  *
   1119  * Action is a bitmask consisting of CURLPAUSE_* bits in curl/curl.h
   1120  *
   1121  * NOTE: This is one of few API functions that are allowed to be called from
   1122  * within a callback.
   1123  */
   1124 CURLcode curl_easy_pause(CURL *d, int action)
   1125 {
   1126   CURLcode result = CURLE_OK;
   1127   bool recursive = FALSE;
   1128   bool changed = FALSE;
   1129   struct Curl_easy *data = d;
   1130   bool recv_paused, recv_paused_new;
   1131   bool send_paused, send_paused_new;
   1132 
   1133   if(!GOOD_EASY_HANDLE(data) || !data->conn)
   1134     /* crazy input, do not continue */
   1135     return CURLE_BAD_FUNCTION_ARGUMENT;
   1136 
   1137   if(Curl_is_in_callback(data))
   1138     recursive = TRUE;
   1139 
   1140   recv_paused = Curl_xfer_recv_is_paused(data);
   1141   recv_paused_new = (action & CURLPAUSE_RECV);
   1142   send_paused = Curl_xfer_send_is_paused(data);
   1143   send_paused_new = (action & CURLPAUSE_SEND);
   1144 
   1145   if(send_paused != send_paused_new) {
   1146     changed = TRUE;
   1147     result = Curl_1st_err(result, Curl_xfer_pause_send(data, send_paused_new));
   1148   }
   1149 
   1150   if(recv_paused != recv_paused_new) {
   1151     changed = TRUE;
   1152     result = Curl_1st_err(result, Curl_xfer_pause_recv(data, recv_paused_new));
   1153   }
   1154 
   1155   /* If not completely pausing both directions now, run again in any case. */
   1156   if(!Curl_xfer_is_blocked(data)) {
   1157     Curl_expire(data, 0, EXPIRE_RUN_NOW);
   1158     /* reset the too-slow time keeper */
   1159     data->state.keeps_speed.tv_sec = 0;
   1160     /* On changes, tell application to update its timers. */
   1161     if(changed && data->multi) {
   1162       if(Curl_update_timer(data->multi) && !result)
   1163         result = CURLE_ABORTED_BY_CALLBACK;
   1164     }
   1165   }
   1166 
   1167   if(!result && changed && !data->state.done && data->multi)
   1168     /* pause/unpausing may result in multi event changes */
   1169     if(Curl_multi_ev_assess_xfer(data->multi, data) && !result)
   1170       result = CURLE_ABORTED_BY_CALLBACK;
   1171 
   1172   if(recursive)
   1173     /* this might have called a callback recursively which might have set this
   1174        to false again on exit */
   1175     Curl_set_in_callback(data, TRUE);
   1176 
   1177   return result;
   1178 }
   1179 
   1180 
   1181 static CURLcode easy_connection(struct Curl_easy *data,
   1182                                 struct connectdata **connp)
   1183 {
   1184   curl_socket_t sfd;
   1185 
   1186   if(!data)
   1187     return CURLE_BAD_FUNCTION_ARGUMENT;
   1188 
   1189   /* only allow these to be called on handles with CURLOPT_CONNECT_ONLY */
   1190   if(!data->set.connect_only) {
   1191     failf(data, "CONNECT_ONLY is required");
   1192     return CURLE_UNSUPPORTED_PROTOCOL;
   1193   }
   1194 
   1195   sfd = Curl_getconnectinfo(data, connp);
   1196 
   1197   if(sfd == CURL_SOCKET_BAD) {
   1198     failf(data, "Failed to get recent socket");
   1199     return CURLE_UNSUPPORTED_PROTOCOL;
   1200   }
   1201 
   1202   return CURLE_OK;
   1203 }
   1204 
   1205 /*
   1206  * Receives data from the connected socket. Use after successful
   1207  * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
   1208  * Returns CURLE_OK on success, error code on error.
   1209  */
   1210 CURLcode curl_easy_recv(CURL *d, void *buffer, size_t buflen, size_t *n)
   1211 {
   1212   CURLcode result;
   1213   struct connectdata *c;
   1214   struct Curl_easy *data = d;
   1215 
   1216   if(Curl_is_in_callback(data))
   1217     return CURLE_RECURSIVE_API_CALL;
   1218 
   1219   result = easy_connection(data, &c);
   1220   if(result)
   1221     return result;
   1222 
   1223   if(!data->conn)
   1224     /* on first invoke, the transfer has been detached from the connection and
   1225        needs to be reattached */
   1226     Curl_attach_connection(data, c);
   1227 
   1228   *n = 0;
   1229   return Curl_conn_recv(data, FIRSTSOCKET, buffer, buflen, n);
   1230 }
   1231 
   1232 #ifndef CURL_DISABLE_WEBSOCKETS
   1233 CURLcode Curl_connect_only_attach(struct Curl_easy *data)
   1234 {
   1235   CURLcode result;
   1236   struct connectdata *c = NULL;
   1237 
   1238   result = easy_connection(data, &c);
   1239   if(result)
   1240     return result;
   1241 
   1242   if(!data->conn)
   1243     /* on first invoke, the transfer has been detached from the connection and
   1244        needs to be reattached */
   1245     Curl_attach_connection(data, c);
   1246 
   1247   return CURLE_OK;
   1248 }
   1249 #endif /* !CURL_DISABLE_WEBSOCKETS */
   1250 
   1251 /*
   1252  * Sends data over the connected socket.
   1253  *
   1254  * This is the private internal version of curl_easy_send()
   1255  */
   1256 CURLcode Curl_senddata(struct Curl_easy *data, const void *buffer,
   1257                        size_t buflen, size_t *n)
   1258 {
   1259   CURLcode result;
   1260   struct connectdata *c = NULL;
   1261   SIGPIPE_VARIABLE(pipe_st);
   1262 
   1263   *n = 0;
   1264   result = easy_connection(data, &c);
   1265   if(result)
   1266     return result;
   1267 
   1268   if(!data->conn)
   1269     /* on first invoke, the transfer has been detached from the connection and
   1270        needs to be reattached */
   1271     Curl_attach_connection(data, c);
   1272 
   1273   sigpipe_ignore(data, &pipe_st);
   1274   result = Curl_conn_send(data, FIRSTSOCKET, buffer, buflen, FALSE, n);
   1275   sigpipe_restore(&pipe_st);
   1276 
   1277   if(result && result != CURLE_AGAIN)
   1278     return CURLE_SEND_ERROR;
   1279   return result;
   1280 }
   1281 
   1282 /*
   1283  * Sends data over the connected socket. Use after successful
   1284  * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
   1285  */
   1286 CURLcode curl_easy_send(CURL *d, const void *buffer, size_t buflen, size_t *n)
   1287 {
   1288   size_t written = 0;
   1289   CURLcode result;
   1290   struct Curl_easy *data = d;
   1291   if(Curl_is_in_callback(data))
   1292     return CURLE_RECURSIVE_API_CALL;
   1293 
   1294   result = Curl_senddata(data, buffer, buflen, &written);
   1295   *n = written;
   1296   return result;
   1297 }
   1298 
   1299 /*
   1300  * Performs connection upkeep for the given session handle.
   1301  */
   1302 CURLcode curl_easy_upkeep(CURL *d)
   1303 {
   1304   struct Curl_easy *data = d;
   1305   /* Verify that we got an easy handle we can work with. */
   1306   if(!GOOD_EASY_HANDLE(data))
   1307     return CURLE_BAD_FUNCTION_ARGUMENT;
   1308 
   1309   if(Curl_is_in_callback(data))
   1310     return CURLE_RECURSIVE_API_CALL;
   1311 
   1312   /* Use the common function to keep connections alive. */
   1313   return Curl_cpool_upkeep(data);
   1314 }
   1315 
   1316 CURLcode curl_easy_ssls_import(CURL *d, const char *session_key,
   1317                                const unsigned char *shmac, size_t shmac_len,
   1318                                const unsigned char *sdata, size_t sdata_len)
   1319 {
   1320 #ifdef USE_SSLS_EXPORT
   1321   struct Curl_easy *data = d;
   1322   if(!GOOD_EASY_HANDLE(data))
   1323     return CURLE_BAD_FUNCTION_ARGUMENT;
   1324   return Curl_ssl_session_import(data, session_key,
   1325                                  shmac, shmac_len, sdata, sdata_len);
   1326 #else
   1327   (void)d;
   1328   (void)session_key;
   1329   (void)shmac;
   1330   (void)shmac_len;
   1331   (void)sdata;
   1332   (void)sdata_len;
   1333   return CURLE_NOT_BUILT_IN;
   1334 #endif
   1335 }
   1336 
   1337 CURLcode curl_easy_ssls_export(CURL *d,
   1338                                curl_ssls_export_cb *export_fn,
   1339                                void *userptr)
   1340 {
   1341 #ifdef USE_SSLS_EXPORT
   1342   struct Curl_easy *data = d;
   1343   if(!GOOD_EASY_HANDLE(data))
   1344     return CURLE_BAD_FUNCTION_ARGUMENT;
   1345   return Curl_ssl_session_export(data, export_fn, userptr);
   1346 #else
   1347   (void)d;
   1348   (void)export_fn;
   1349   (void)userptr;
   1350   return CURLE_NOT_BUILT_IN;
   1351 #endif
   1352 }
   1353 
   1354 CURLcode Curl_meta_set(struct Curl_easy *data, const char *key,
   1355                        void *meta_data, Curl_meta_dtor *meta_dtor)
   1356 {
   1357   DEBUGASSERT(meta_data); /* never set to NULL */
   1358   if(!Curl_hash_add2(&data->meta_hash, CURL_UNCONST(key), strlen(key) + 1,
   1359                      meta_data, meta_dtor)) {
   1360     meta_dtor(CURL_UNCONST(key), strlen(key) + 1, meta_data);
   1361     return CURLE_OUT_OF_MEMORY;
   1362   }
   1363   return CURLE_OK;
   1364 }
   1365 
   1366 void Curl_meta_remove(struct Curl_easy *data, const char *key)
   1367 {
   1368   Curl_hash_delete(&data->meta_hash, CURL_UNCONST(key), strlen(key) + 1);
   1369 }
   1370 
   1371 void *Curl_meta_get(struct Curl_easy *data, const char *key)
   1372 {
   1373   return Curl_hash_pick(&data->meta_hash, CURL_UNCONST(key), strlen(key) + 1);
   1374 }
   1375 
   1376 void Curl_meta_reset(struct Curl_easy *data)
   1377 {
   1378   Curl_hash_clean(&data->meta_hash);
   1379 }