Resync
[CMakeLuaTailorHgBridge.git] / CMakeLua / Utilities / cmcurl / easy.c
blob28d5a5188fca5c6d123e6585a388d468420166a1
1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
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 http://curl.haxx.se/docs/copyright.html.
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 * $Id: easy.c,v 1.2 2007/03/15 19:22:13 andy Exp $
22 ***************************************************************************/
24 #include "setup.h"
26 /* -- WIN32 approved -- */
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdarg.h>
30 #include <stdlib.h>
31 #include <ctype.h>
32 #ifdef HAVE_SYS_TYPES_H
33 #include <sys/types.h>
34 #endif
35 #ifdef HAVE_SYS_STAT_H
36 #include <sys/stat.h>
37 #endif
39 #include <errno.h>
41 #include "strequal.h"
43 #ifdef WIN32
44 #include <time.h>
45 #include <io.h>
46 #else
47 #ifdef HAVE_SYS_SOCKET_H
48 #include <sys/socket.h>
49 #endif
50 #include <netinet/in.h>
51 #ifdef HAVE_SYS_TIME_H
52 #include <sys/time.h>
53 #endif
54 #ifdef HAVE_UNISTD_H
55 #include <unistd.h>
56 #endif
57 #include <netdb.h>
58 #ifdef HAVE_ARPA_INET_H
59 #include <arpa/inet.h>
60 #endif
61 #ifdef HAVE_NET_IF_H
62 #include <net/if.h>
63 #endif
64 #include <sys/ioctl.h>
65 #include <signal.h>
67 #ifdef HAVE_SYS_PARAM_H
68 #include <sys/param.h>
69 #endif
71 #ifdef HAVE_SYS_SELECT_H
72 #include <sys/select.h>
73 #endif
75 #endif /* WIN32 ... */
77 #include "urldata.h"
78 #include <curl/curl.h>
79 #include "transfer.h"
80 #include "sslgen.h"
81 #include "url.h"
82 #include "getinfo.h"
83 #include "hostip.h"
84 #include "share.h"
85 #include "strdup.h"
86 #include "memory.h"
87 #include "progress.h"
88 #include "easyif.h"
89 #include "sendf.h" /* for failf function prototype */
90 #include <ca-bundle.h>
92 #define _MPRINTF_REPLACE /* use our functions only */
93 #include <curl/mprintf.h>
95 #if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
96 #include <iconv.h>
97 /* set default codesets for iconv */
98 #ifndef CURL_ICONV_CODESET_OF_NETWORK
99 #define CURL_ICONV_CODESET_OF_NETWORK "ISO8859-1"
100 #endif
101 #ifndef CURL_ICONV_CODESET_FOR_UTF8
102 #define CURL_ICONV_CODESET_FOR_UTF8 "UTF-8"
103 #endif
104 #define ICONV_ERROR (size_t)-1
105 #endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */
107 /* The last #include file should be: */
108 #include "memdebug.h"
110 #ifdef USE_WINSOCK
111 /* win32_cleanup() is for win32 socket cleanup functionality, the opposite
112 of win32_init() */
113 static void win32_cleanup(void)
115 WSACleanup();
118 /* win32_init() performs win32 socket initialization to properly setup the
119 stack to allow networking */
120 static CURLcode win32_init(void)
122 WORD wVersionRequested;
123 WSADATA wsaData;
124 int err;
126 #if defined(ENABLE_IPV6) && (USE_WINSOCK < 2)
127 Error IPV6_requires_winsock2
128 #endif
130 wVersionRequested = MAKEWORD(USE_WINSOCK, USE_WINSOCK);
132 err = WSAStartup(wVersionRequested, &wsaData);
134 if (err != 0)
135 /* Tell the user that we couldn't find a useable */
136 /* winsock.dll. */
137 return CURLE_FAILED_INIT;
139 /* Confirm that the Windows Sockets DLL supports what we need.*/
140 /* Note that if the DLL supports versions greater */
141 /* than wVersionRequested, it will still return */
142 /* wVersionRequested in wVersion. wHighVersion contains the */
143 /* highest supported version. */
145 if ( LOBYTE( wsaData.wVersion ) != LOBYTE(wVersionRequested) ||
146 HIBYTE( wsaData.wVersion ) != HIBYTE(wVersionRequested) ) {
147 /* Tell the user that we couldn't find a useable */
149 /* winsock.dll. */
150 WSACleanup();
151 return CURLE_FAILED_INIT;
153 /* The Windows Sockets DLL is acceptable. Proceed. */
154 return CURLE_OK;
157 #else
158 /* These functions exist merely to prevent compiler warnings */
159 static CURLcode win32_init(void) { return CURLE_OK; }
160 static void win32_cleanup(void) { }
161 #endif
163 #ifdef USE_LIBIDN
165 * Initialise use of IDNA library.
166 * It falls back to ASCII if $CHARSET isn't defined. This doesn't work for
167 * idna_to_ascii_lz().
169 static void idna_init (void)
171 #ifdef WIN32
172 char buf[60];
173 UINT cp = GetACP();
175 if (!getenv("CHARSET") && cp > 0) {
176 snprintf(buf, sizeof(buf), "CHARSET=cp%u", cp);
177 putenv(buf);
179 #else
180 /* to do? */
181 #endif
183 #endif /* USE_LIBIDN */
185 /* true globals -- for curl_global_init() and curl_global_cleanup() */
186 static unsigned int initialized;
187 static long init_flags;
190 * strdup (and other memory functions) is redefined in complicated
191 * ways, but at this point it must be defined as the system-supplied strdup
192 * so the callback pointer is initialized correctly.
194 #if defined(_WIN32_WCE)
195 #define system_strdup _strdup
196 #elif !defined(HAVE_STRDUP)
197 #define system_strdup curlx_strdup
198 #else
199 #define system_strdup strdup
200 #endif
203 * If a memory-using function (like curl_getenv) is used before
204 * curl_global_init() is called, we need to have these pointers set already.
207 curl_malloc_callback Curl_cmalloc = (curl_malloc_callback)malloc;
208 curl_free_callback Curl_cfree = (curl_free_callback)free;
209 curl_realloc_callback Curl_crealloc = (curl_realloc_callback)realloc;
210 curl_strdup_callback Curl_cstrdup = (curl_strdup_callback)system_strdup;
211 curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc;
214 * curl_global_init() globally initializes cURL given a bitwise set of the
215 * different features of what to initialize.
217 CURLcode curl_global_init(long flags)
219 if (initialized++)
220 return CURLE_OK;
222 /* Setup the default memory functions here (again) */
223 Curl_cmalloc = (curl_malloc_callback)malloc;
224 Curl_cfree = (curl_free_callback)free;
225 Curl_crealloc = (curl_realloc_callback)realloc;
226 Curl_cstrdup = (curl_strdup_callback)system_strdup;
227 Curl_ccalloc = (curl_calloc_callback)calloc;
229 if (flags & CURL_GLOBAL_SSL)
230 if (!Curl_ssl_init())
231 return CURLE_FAILED_INIT;
233 if (flags & CURL_GLOBAL_WIN32)
234 if (win32_init() != CURLE_OK)
235 return CURLE_FAILED_INIT;
237 #ifdef _AMIGASF
238 if(!amiga_init())
239 return CURLE_FAILED_INIT;
240 #endif
242 #ifdef USE_LIBIDN
243 idna_init();
244 #endif
246 init_flags = flags;
248 return CURLE_OK;
252 * curl_global_init_mem() globally initializes cURL and also registers the
253 * user provided callback routines.
255 CURLcode curl_global_init_mem(long flags, curl_malloc_callback m,
256 curl_free_callback f, curl_realloc_callback r,
257 curl_strdup_callback s, curl_calloc_callback c)
259 CURLcode code = CURLE_OK;
261 /* Invalid input, return immediately */
262 if (!m || !f || !r || !s || !c)
263 return CURLE_FAILED_INIT;
265 /* Already initialized, don't do it again */
266 if ( initialized )
267 return CURLE_OK;
269 /* Call the actual init function first */
270 code = curl_global_init(flags);
271 if (code == CURLE_OK) {
272 Curl_cmalloc = m;
273 Curl_cfree = f;
274 Curl_cstrdup = s;
275 Curl_crealloc = r;
276 Curl_ccalloc = c;
279 return code;
283 * curl_global_cleanup() globally cleanups cURL, uses the value of
284 * "init_flags" to determine what needs to be cleaned up and what doesn't.
286 void curl_global_cleanup(void)
288 if (!initialized)
289 return;
291 if (--initialized)
292 return;
294 Curl_global_host_cache_dtor();
296 if (init_flags & CURL_GLOBAL_SSL)
297 Curl_ssl_cleanup();
299 if (init_flags & CURL_GLOBAL_WIN32)
300 win32_cleanup();
302 #ifdef _AMIGASF
303 amiga_cleanup();
304 #endif
306 init_flags = 0;
310 * curl_easy_init() is the external interface to alloc, setup and init an
311 * easy handle that is returned. If anything goes wrong, NULL is returned.
313 CURL *curl_easy_init(void)
315 CURLcode res;
316 struct SessionHandle *data;
318 /* Make sure we inited the global SSL stuff */
319 if (!initialized) {
320 res = curl_global_init(CURL_GLOBAL_DEFAULT);
321 if(res)
322 /* something in the global init failed, return nothing */
323 return NULL;
326 /* We use curl_open() with undefined URL so far */
327 res = Curl_open(&data);
328 if(res != CURLE_OK)
329 return NULL;
331 return data;
335 * curl_easy_setopt() is the external interface for setting options on an
336 * easy handle.
339 CURLcode curl_easy_setopt(CURL *curl, CURLoption tag, ...)
341 va_list arg;
342 struct SessionHandle *data = curl;
343 CURLcode ret;
345 if(!curl)
346 return CURLE_BAD_FUNCTION_ARGUMENT;
348 va_start(arg, tag);
350 ret = Curl_setopt(data, tag, arg);
352 va_end(arg);
353 return ret;
356 #ifdef CURL_MULTIEASY
357 /***************************************************************************
358 * This function is still only for testing purposes. It makes a great way
359 * to run the full test suite on the multi interface instead of the easy one.
360 ***************************************************************************
362 * The *new* curl_easy_perform() is the external interface that performs a
363 * transfer previously setup.
365 * Wrapper-function that: creates a multi handle, adds the easy handle to it,
366 * runs curl_multi_perform() until the transfer is done, then detaches the
367 * easy handle, destroys the multi handle and returns the easy handle's return
368 * code. This will make everything internally use and assume multi interface.
370 CURLcode curl_easy_perform(CURL *easy)
372 CURLM *multi;
373 CURLMcode mcode;
374 CURLcode code = CURLE_OK;
375 int still_running;
376 struct timeval timeout;
377 int rc;
378 CURLMsg *msg;
379 fd_set fdread;
380 fd_set fdwrite;
381 fd_set fdexcep;
382 int maxfd;
384 if(!easy)
385 return CURLE_BAD_FUNCTION_ARGUMENT;
387 multi = curl_multi_init();
388 if(!multi)
389 return CURLE_OUT_OF_MEMORY;
391 mcode = curl_multi_add_handle(multi, easy);
392 if(mcode) {
393 curl_multi_cleanup(multi);
394 return CURLE_FAILED_INIT;
397 /* we start some action by calling perform right away */
399 do {
400 while(CURLM_CALL_MULTI_PERFORM ==
401 curl_multi_perform(multi, &still_running));
403 if(!still_running)
404 break;
406 FD_ZERO(&fdread);
407 FD_ZERO(&fdwrite);
408 FD_ZERO(&fdexcep);
410 /* timeout once per second */
411 timeout.tv_sec = 1;
412 timeout.tv_usec = 0;
414 /* get file descriptors from the transfers */
415 curl_multi_fdset(multi, &fdread, &fdwrite, &fdexcep, &maxfd);
417 rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
419 if(rc == -1)
420 /* select error */
421 break;
423 /* timeout or data to send/receive => loop! */
424 } while(still_running);
426 msg = curl_multi_info_read(multi, &rc);
427 if(msg)
428 code = msg->data.result;
430 mcode = curl_multi_remove_handle(multi, easy);
431 /* what to do if it fails? */
433 mcode = curl_multi_cleanup(multi);
434 /* what to do if it fails? */
436 return code;
438 #else
440 * curl_easy_perform() is the external interface that performs a transfer
441 * previously setup.
443 CURLcode curl_easy_perform(CURL *curl)
445 struct SessionHandle *data = (struct SessionHandle *)curl;
447 if(!data)
448 return CURLE_BAD_FUNCTION_ARGUMENT;
450 if ( ! (data->share && data->share->hostcache) ) {
452 if (Curl_global_host_cache_use(data) &&
453 (data->dns.hostcachetype != HCACHE_GLOBAL)) {
454 if (data->dns.hostcachetype == HCACHE_PRIVATE)
455 Curl_hash_destroy(data->dns.hostcache);
456 data->dns.hostcache = Curl_global_host_cache_get();
457 data->dns.hostcachetype = HCACHE_GLOBAL;
460 if (!data->dns.hostcache) {
461 data->dns.hostcachetype = HCACHE_PRIVATE;
462 data->dns.hostcache = Curl_mk_dnscache();
464 if(!data->dns.hostcache)
465 /* While we possibly could survive and do good without a host cache,
466 the fact that creating it failed indicates that things are truly
467 screwed up and we should bail out! */
468 return CURLE_OUT_OF_MEMORY;
473 if(!data->state.connc) {
474 /* oops, no connection cache, make one up */
475 data->state.connc = Curl_mk_connc(CONNCACHE_PRIVATE, -1);
476 if(!data->state.connc)
477 return CURLE_OUT_OF_MEMORY;
480 return Curl_perform(data);
482 #endif
485 * curl_easy_cleanup() is the external interface to cleaning/freeing the given
486 * easy handle.
488 void curl_easy_cleanup(CURL *curl)
490 struct SessionHandle *data = (struct SessionHandle *)curl;
492 if(!data)
493 return;
495 Curl_close(data);
499 * Store a pointed to the multi handle within the easy handle's data struct.
501 void Curl_easy_addmulti(struct SessionHandle *data,
502 void *multi)
504 data->multi = multi;
507 void Curl_easy_initHandleData(struct SessionHandle *data)
509 memset(&data->reqdata, 0, sizeof(struct HandleData));
511 data->reqdata.maxdownload = -1;
515 * curl_easy_getinfo() is an external interface that allows an app to retrieve
516 * information from a performed transfer and similar.
518 CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...)
520 va_list arg;
521 void *paramp;
522 struct SessionHandle *data = (struct SessionHandle *)curl;
524 va_start(arg, info);
525 paramp = va_arg(arg, void *);
527 return Curl_getinfo(data, info, paramp);
531 * curl_easy_duphandle() is an external interface to allow duplication of a
532 * given input easy handle. The returned handle will be a new working handle
533 * with all options set exactly as the input source handle.
535 CURL *curl_easy_duphandle(CURL *incurl)
537 bool fail = TRUE;
538 struct SessionHandle *data=(struct SessionHandle *)incurl;
540 struct SessionHandle *outcurl = (struct SessionHandle *)
541 calloc(sizeof(struct SessionHandle), 1);
543 if(NULL == outcurl)
544 return NULL; /* failure */
546 do {
549 * We setup a few buffers we need. We should probably make them
550 * get setup on-demand in the code, as that would probably decrease
551 * the likeliness of us forgetting to init a buffer here in the future.
553 outcurl->state.headerbuff=(char*)malloc(HEADERSIZE);
554 if(!outcurl->state.headerbuff) {
555 break;
557 outcurl->state.headersize=HEADERSIZE;
559 /* copy all userdefined values */
560 outcurl->set = data->set;
562 if(data->state.used_interface == Curl_if_multi)
563 outcurl->state.connc = data->state.connc;
564 else
565 outcurl->state.connc = Curl_mk_connc(CONNCACHE_PRIVATE, -1);
567 if(!outcurl->state.connc)
568 break;
570 outcurl->state.lastconnect = -1;
572 outcurl->progress.flags = data->progress.flags;
573 outcurl->progress.callback = data->progress.callback;
575 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
576 if(data->cookies) {
577 /* If cookies are enabled in the parent handle, we enable them
578 in the clone as well! */
579 outcurl->cookies = Curl_cookie_init(data,
580 data->cookies->filename,
581 outcurl->cookies,
582 data->set.cookiesession);
583 if(!outcurl->cookies) {
584 break;
587 #endif /* CURL_DISABLE_HTTP */
589 /* duplicate all values in 'change' */
591 if(data->change.url) {
592 outcurl->change.url = strdup(data->change.url);
593 if(!outcurl->change.url)
594 break;
595 outcurl->change.url_alloc = TRUE;
598 if(data->change.referer) {
599 outcurl->change.referer = strdup(data->change.referer);
600 if(!outcurl->change.referer)
601 break;
602 outcurl->change.referer_alloc = TRUE;
605 #ifdef USE_ARES
606 /* If we use ares, we setup a new ares channel for the new handle */
607 if(ARES_SUCCESS != ares_init(&outcurl->state.areschannel))
608 break;
609 #endif
611 #if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
612 outcurl->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
613 CURL_ICONV_CODESET_OF_NETWORK);
614 outcurl->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
615 CURL_ICONV_CODESET_OF_HOST);
616 outcurl->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
617 CURL_ICONV_CODESET_FOR_UTF8);
618 #endif
620 Curl_easy_initHandleData(outcurl);
622 outcurl->magic = CURLEASY_MAGIC_NUMBER;
624 fail = FALSE; /* we reach this point and thus we are OK */
626 } while(0);
628 if(fail) {
629 if(outcurl) {
630 if(outcurl->state.connc->type == CONNCACHE_PRIVATE)
631 Curl_rm_connc(outcurl->state.connc);
632 if(outcurl->state.headerbuff)
633 free(outcurl->state.headerbuff);
634 if(outcurl->change.url)
635 free(outcurl->change.url);
636 if(outcurl->change.referer)
637 free(outcurl->change.referer);
638 free(outcurl); /* free the memory again */
639 outcurl = NULL;
643 return outcurl;
647 * curl_easy_reset() is an external interface that allows an app to re-
648 * initialize a session handle to the default values.
650 void curl_easy_reset(CURL *curl)
652 struct SessionHandle *data = (struct SessionHandle *)curl;
654 Curl_safefree(data->reqdata.pathbuffer);
655 data->reqdata.pathbuffer=NULL;
657 Curl_safefree(data->reqdata.proto.generic);
658 data->reqdata.proto.generic=NULL;
660 /* zero out UserDefined data: */
661 memset(&data->set, 0, sizeof(struct UserDefined));
663 /* zero out Progress data: */
664 memset(&data->progress, 0, sizeof(struct Progress));
666 /* init Handle data */
667 Curl_easy_initHandleData(data);
669 /* The remainder of these calls have been taken from Curl_open() */
671 data->set.out = stdout; /* default output to stdout */
672 data->set.in = stdin; /* default input from stdin */
673 data->set.err = stderr; /* default stderr to stderr */
675 /* use fwrite as default function to store output */
676 data->set.fwrite = (curl_write_callback)fwrite;
678 /* use fread as default function to read input */
679 data->set.fread = (curl_read_callback)fread;
681 data->set.infilesize = -1; /* we don't know any size */
682 data->set.postfieldsize = -1;
684 data->state.current_speed = -1; /* init to negative == impossible */
686 data->set.httpreq = HTTPREQ_GET; /* Default HTTP request */
687 data->set.ftp_use_epsv = TRUE; /* FTP defaults to EPSV operations */
688 data->set.ftp_use_eprt = TRUE; /* FTP defaults to EPRT operations */
690 data->set.dns_cache_timeout = 60; /* Timeout every 60 seconds by default */
692 /* make libcurl quiet by default: */
693 data->set.hide_progress = TRUE; /* CURLOPT_NOPROGRESS changes these */
694 data->progress.flags |= PGRS_HIDE;
696 /* Set the default size of the SSL session ID cache */
697 data->set.ssl.numsessions = 5;
699 data->set.proxyport = 1080;
700 data->set.proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */
701 data->set.httpauth = CURLAUTH_BASIC; /* defaults to basic */
702 data->set.proxyauth = CURLAUTH_BASIC; /* defaults to basic */
705 * libcurl 7.10 introduced SSL verification *by default*! This needs to be
706 * switched off unless wanted.
708 data->set.ssl.verifypeer = TRUE;
709 data->set.ssl.verifyhost = 2;
710 #ifdef CURL_CA_BUNDLE
711 /* This is our prefered CA cert bundle since install time */
712 data->set.ssl.CAfile = (char *)CURL_CA_BUNDLE;
713 #endif
715 data->set.ssh_auth_types = CURLSSH_AUTH_DEFAULT; /* defaults to any auth
716 type */
719 #ifdef CURL_DOES_CONVERSIONS
721 * Curl_convert_to_network() is an internal function
722 * for performing ASCII conversions on non-ASCII platforms.
724 CURLcode Curl_convert_to_network(struct SessionHandle *data,
725 char *buffer, size_t length)
727 CURLcode rc;
729 if(data->set.convtonetwork) {
730 /* use translation callback */
731 rc = data->set.convtonetwork(buffer, length);
732 if(rc != CURLE_OK) {
733 failf(data,
734 "CURLOPT_CONV_TO_NETWORK_FUNCTION callback returned %i: %s",
735 rc, curl_easy_strerror(rc));
737 return(rc);
738 } else {
739 #ifdef HAVE_ICONV
740 /* do the translation ourselves */
741 char *input_ptr, *output_ptr;
742 size_t in_bytes, out_bytes, rc;
744 /* open an iconv conversion descriptor if necessary */
745 if(data->outbound_cd == (iconv_t)-1) {
746 data->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
747 CURL_ICONV_CODESET_OF_HOST);
748 if(data->outbound_cd == (iconv_t)-1) {
749 failf(data,
750 "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
751 CURL_ICONV_CODESET_OF_NETWORK,
752 CURL_ICONV_CODESET_OF_HOST,
753 errno, strerror(errno));
754 return CURLE_CONV_FAILED;
757 /* call iconv */
758 input_ptr = output_ptr = buffer;
759 in_bytes = out_bytes = length;
760 rc = iconv(data->outbound_cd, (const char**)&input_ptr, &in_bytes,
761 &output_ptr, &out_bytes);
762 if ((rc == ICONV_ERROR) || (in_bytes != 0)) {
763 failf(data,
764 "The Curl_convert_to_network iconv call failed with errno %i: %s",
765 errno, strerror(errno));
766 return CURLE_CONV_FAILED;
768 #else
769 failf(data, "CURLOPT_CONV_TO_NETWORK_FUNCTION callback required");
770 return CURLE_CONV_REQD;
771 #endif /* HAVE_ICONV */
774 return CURLE_OK;
778 * Curl_convert_from_network() is an internal function
779 * for performing ASCII conversions on non-ASCII platforms.
781 CURLcode Curl_convert_from_network(struct SessionHandle *data,
782 char *buffer, size_t length)
784 CURLcode rc;
786 if(data->set.convfromnetwork) {
787 /* use translation callback */
788 rc = data->set.convfromnetwork(buffer, length);
789 if(rc != CURLE_OK) {
790 failf(data,
791 "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback returned %i: %s",
792 rc, curl_easy_strerror(rc));
794 return(rc);
795 } else {
796 #ifdef HAVE_ICONV
797 /* do the translation ourselves */
798 char *input_ptr, *output_ptr;
799 size_t in_bytes, out_bytes, rc;
801 /* open an iconv conversion descriptor if necessary */
802 if(data->inbound_cd == (iconv_t)-1) {
803 data->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
804 CURL_ICONV_CODESET_OF_NETWORK);
805 if(data->inbound_cd == (iconv_t)-1) {
806 failf(data,
807 "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
808 CURL_ICONV_CODESET_OF_HOST,
809 CURL_ICONV_CODESET_OF_NETWORK,
810 errno, strerror(errno));
811 return CURLE_CONV_FAILED;
814 /* call iconv */
815 input_ptr = output_ptr = buffer;
816 in_bytes = out_bytes = length;
817 rc = iconv(data->inbound_cd, (const char **)&input_ptr, &in_bytes,
818 &output_ptr, &out_bytes);
819 if ((rc == ICONV_ERROR) || (in_bytes != 0)) {
820 failf(data,
821 "The Curl_convert_from_network iconv call failed with errno %i: %s",
822 errno, strerror(errno));
823 return CURLE_CONV_FAILED;
825 #else
826 failf(data, "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback required");
827 return CURLE_CONV_REQD;
828 #endif /* HAVE_ICONV */
831 return CURLE_OK;
835 * Curl_convert_from_utf8() is an internal function
836 * for performing UTF-8 conversions on non-ASCII platforms.
838 CURLcode Curl_convert_from_utf8(struct SessionHandle *data,
839 char *buffer, size_t length)
841 CURLcode rc;
843 if(data->set.convfromutf8) {
844 /* use translation callback */
845 rc = data->set.convfromutf8(buffer, length);
846 if(rc != CURLE_OK) {
847 failf(data,
848 "CURLOPT_CONV_FROM_UTF8_FUNCTION callback returned %i: %s",
849 rc, curl_easy_strerror(rc));
851 return(rc);
852 } else {
853 #ifdef HAVE_ICONV
854 /* do the translation ourselves */
855 char *input_ptr, *output_ptr;
856 size_t in_bytes, out_bytes, rc;
858 /* open an iconv conversion descriptor if necessary */
859 if(data->utf8_cd == (iconv_t)-1) {
860 data->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
861 CURL_ICONV_CODESET_FOR_UTF8);
862 if(data->utf8_cd == (iconv_t)-1) {
863 failf(data,
864 "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
865 CURL_ICONV_CODESET_OF_HOST,
866 CURL_ICONV_CODESET_FOR_UTF8,
867 errno, strerror(errno));
868 return CURLE_CONV_FAILED;
871 /* call iconv */
872 input_ptr = output_ptr = buffer;
873 in_bytes = out_bytes = length;
874 rc = iconv(data->utf8_cd, (const char**)&input_ptr, &in_bytes,
875 &output_ptr, &out_bytes);
876 if ((rc == ICONV_ERROR) || (in_bytes != 0)) {
877 failf(data,
878 "The Curl_convert_from_utf8 iconv call failed with errno %i: %s",
879 errno, strerror(errno));
880 return CURLE_CONV_FAILED;
882 if (output_ptr < input_ptr) {
883 /* null terminate the now shorter output string */
884 *output_ptr = 0x00;
886 #else
887 failf(data, "CURLOPT_CONV_FROM_UTF8_FUNCTION callback required");
888 return CURLE_CONV_REQD;
889 #endif /* HAVE_ICONV */
892 return CURLE_OK;
895 #endif /* CURL_DOES_CONVERSIONS */