Home | History | Annotate | Download | only in lib
      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel (at) 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.haxx.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  ***************************************************************************/
     22 
     23 #include "curl_setup.h"
     24 
     25 #ifdef CURL_DOES_CONVERSIONS
     26 
     27 #include <curl/curl.h>
     28 
     29 #include "non-ascii.h"
     30 #include "formdata.h"
     31 #include "sendf.h"
     32 #include "urldata.h"
     33 
     34 #include "curl_memory.h"
     35 /* The last #include file should be: */
     36 #include "memdebug.h"
     37 
     38 #ifdef HAVE_ICONV
     39 #include <iconv.h>
     40 /* set default codesets for iconv */
     41 #ifndef CURL_ICONV_CODESET_OF_NETWORK
     42 #define CURL_ICONV_CODESET_OF_NETWORK "ISO8859-1"
     43 #endif
     44 #ifndef CURL_ICONV_CODESET_FOR_UTF8
     45 #define CURL_ICONV_CODESET_FOR_UTF8   "UTF-8"
     46 #endif
     47 #define ICONV_ERROR  (size_t)-1
     48 #endif /* HAVE_ICONV */
     49 
     50 /*
     51  * Curl_convert_clone() returns a malloced copy of the source string (if
     52  * returning CURLE_OK), with the data converted to network format.
     53  */
     54 CURLcode Curl_convert_clone(struct Curl_easy *data,
     55                            const char *indata,
     56                            size_t insize,
     57                            char **outbuf)
     58 {
     59   char *convbuf;
     60   CURLcode result;
     61 
     62   convbuf = malloc(insize);
     63   if(!convbuf)
     64     return CURLE_OUT_OF_MEMORY;
     65 
     66   memcpy(convbuf, indata, insize);
     67   result = Curl_convert_to_network(data, convbuf, insize);
     68   if(result) {
     69     free(convbuf);
     70     return result;
     71   }
     72 
     73   *outbuf = convbuf; /* return the converted buffer */
     74 
     75   return CURLE_OK;
     76 }
     77 
     78 /*
     79  * Curl_convert_to_network() is an internal function for performing ASCII
     80  * conversions on non-ASCII platforms. It convers the buffer _in place_.
     81  */
     82 CURLcode Curl_convert_to_network(struct Curl_easy *data,
     83                                  char *buffer, size_t length)
     84 {
     85   if(data && data->set.convtonetwork) {
     86     /* use translation callback */
     87     CURLcode result = data->set.convtonetwork(buffer, length);
     88     if(result) {
     89       failf(data,
     90             "CURLOPT_CONV_TO_NETWORK_FUNCTION callback returned %d: %s",
     91             (int)result, curl_easy_strerror(result));
     92     }
     93 
     94     return result;
     95   }
     96   else {
     97 #ifdef HAVE_ICONV
     98     /* do the translation ourselves */
     99     iconv_t tmpcd = (iconv_t) -1;
    100     iconv_t *cd = &tmpcd;
    101     char *input_ptr, *output_ptr;
    102     size_t in_bytes, out_bytes, rc;
    103 
    104     /* open an iconv conversion descriptor if necessary */
    105     if(data)
    106       cd = &data->outbound_cd;
    107     if(*cd == (iconv_t)-1) {
    108       *cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
    109                        CURL_ICONV_CODESET_OF_HOST);
    110       if(*cd == (iconv_t)-1) {
    111         failf(data,
    112               "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
    113               CURL_ICONV_CODESET_OF_NETWORK,
    114               CURL_ICONV_CODESET_OF_HOST,
    115               errno, strerror(errno));
    116         return CURLE_CONV_FAILED;
    117       }
    118     }
    119     /* call iconv */
    120     input_ptr = output_ptr = buffer;
    121     in_bytes = out_bytes = length;
    122     rc = iconv(*cd, &input_ptr, &in_bytes,
    123                &output_ptr, &out_bytes);
    124     if(!data)
    125       iconv_close(tmpcd);
    126     if((rc == ICONV_ERROR) || (in_bytes != 0)) {
    127       failf(data,
    128             "The Curl_convert_to_network iconv call failed with errno %i: %s",
    129             errno, strerror(errno));
    130       return CURLE_CONV_FAILED;
    131     }
    132 #else
    133     failf(data, "CURLOPT_CONV_TO_NETWORK_FUNCTION callback required");
    134     return CURLE_CONV_REQD;
    135 #endif /* HAVE_ICONV */
    136   }
    137 
    138   return CURLE_OK;
    139 }
    140 
    141 /*
    142  * Curl_convert_from_network() is an internal function for performing ASCII
    143  * conversions on non-ASCII platforms. It convers the buffer _in place_.
    144  */
    145 CURLcode Curl_convert_from_network(struct Curl_easy *data,
    146                                    char *buffer, size_t length)
    147 {
    148   if(data && data->set.convfromnetwork) {
    149     /* use translation callback */
    150     CURLcode result = data->set.convfromnetwork(buffer, length);
    151     if(result) {
    152       failf(data,
    153             "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback returned %d: %s",
    154             (int)result, curl_easy_strerror(result));
    155     }
    156 
    157     return result;
    158   }
    159   else {
    160 #ifdef HAVE_ICONV
    161     /* do the translation ourselves */
    162     iconv_t tmpcd = (iconv_t) -1;
    163     iconv_t *cd = &tmpcd;
    164     char *input_ptr, *output_ptr;
    165     size_t in_bytes, out_bytes, rc;
    166 
    167     /* open an iconv conversion descriptor if necessary */
    168     if(data)
    169       cd = &data->inbound_cd;
    170     if(*cd == (iconv_t)-1) {
    171       *cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
    172                        CURL_ICONV_CODESET_OF_NETWORK);
    173       if(*cd == (iconv_t)-1) {
    174         failf(data,
    175               "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
    176               CURL_ICONV_CODESET_OF_HOST,
    177               CURL_ICONV_CODESET_OF_NETWORK,
    178               errno, strerror(errno));
    179         return CURLE_CONV_FAILED;
    180       }
    181     }
    182     /* call iconv */
    183     input_ptr = output_ptr = buffer;
    184     in_bytes = out_bytes = length;
    185     rc = iconv(*cd, &input_ptr, &in_bytes,
    186                &output_ptr, &out_bytes);
    187     if(!data)
    188       iconv_close(tmpcd);
    189     if((rc == ICONV_ERROR) || (in_bytes != 0)) {
    190       failf(data,
    191             "Curl_convert_from_network iconv call failed with errno %i: %s",
    192             errno, strerror(errno));
    193       return CURLE_CONV_FAILED;
    194     }
    195 #else
    196     failf(data, "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback required");
    197     return CURLE_CONV_REQD;
    198 #endif /* HAVE_ICONV */
    199   }
    200 
    201   return CURLE_OK;
    202 }
    203 
    204 /*
    205  * Curl_convert_from_utf8() is an internal function for performing UTF-8
    206  * conversions on non-ASCII platforms.
    207  */
    208 CURLcode Curl_convert_from_utf8(struct Curl_easy *data,
    209                                 char *buffer, size_t length)
    210 {
    211   if(data && data->set.convfromutf8) {
    212     /* use translation callback */
    213     CURLcode result = data->set.convfromutf8(buffer, length);
    214     if(result) {
    215       failf(data,
    216             "CURLOPT_CONV_FROM_UTF8_FUNCTION callback returned %d: %s",
    217             (int)result, curl_easy_strerror(result));
    218     }
    219 
    220     return result;
    221   }
    222   else {
    223 #ifdef HAVE_ICONV
    224     /* do the translation ourselves */
    225     iconv_t tmpcd = (iconv_t) -1;
    226     iconv_t *cd = &tmpcd;
    227     char *input_ptr;
    228     char *output_ptr;
    229     size_t in_bytes, out_bytes, rc;
    230 
    231     /* open an iconv conversion descriptor if necessary */
    232     if(data)
    233       cd = &data->utf8_cd;
    234     if(*cd == (iconv_t)-1) {
    235       *cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
    236                        CURL_ICONV_CODESET_FOR_UTF8);
    237       if(*cd == (iconv_t)-1) {
    238         failf(data,
    239               "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
    240               CURL_ICONV_CODESET_OF_HOST,
    241               CURL_ICONV_CODESET_FOR_UTF8,
    242               errno, strerror(errno));
    243         return CURLE_CONV_FAILED;
    244       }
    245     }
    246     /* call iconv */
    247     input_ptr = output_ptr = buffer;
    248     in_bytes = out_bytes = length;
    249     rc = iconv(*cd, &input_ptr, &in_bytes,
    250                &output_ptr, &out_bytes);
    251     if(!data)
    252       iconv_close(tmpcd);
    253     if((rc == ICONV_ERROR) || (in_bytes != 0)) {
    254       failf(data,
    255             "The Curl_convert_from_utf8 iconv call failed with errno %i: %s",
    256             errno, strerror(errno));
    257       return CURLE_CONV_FAILED;
    258     }
    259     if(output_ptr < input_ptr) {
    260       /* null terminate the now shorter output string */
    261       *output_ptr = 0x00;
    262     }
    263 #else
    264     failf(data, "CURLOPT_CONV_FROM_UTF8_FUNCTION callback required");
    265     return CURLE_CONV_REQD;
    266 #endif /* HAVE_ICONV */
    267   }
    268 
    269   return CURLE_OK;
    270 }
    271 
    272 /*
    273  * Init conversion stuff for a Curl_easy
    274  */
    275 void Curl_convert_init(struct Curl_easy *data)
    276 {
    277 #if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
    278   /* conversion descriptors for iconv calls */
    279   data->outbound_cd = (iconv_t)-1;
    280   data->inbound_cd  = (iconv_t)-1;
    281   data->utf8_cd     = (iconv_t)-1;
    282 #else
    283   (void)data;
    284 #endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */
    285 }
    286 
    287 /*
    288  * Setup conversion stuff for a Curl_easy
    289  */
    290 void Curl_convert_setup(struct Curl_easy *data)
    291 {
    292   data->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
    293                                 CURL_ICONV_CODESET_OF_NETWORK);
    294   data->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
    295                                  CURL_ICONV_CODESET_OF_HOST);
    296   data->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
    297                              CURL_ICONV_CODESET_FOR_UTF8);
    298 }
    299 
    300 /*
    301  * Close conversion stuff for a Curl_easy
    302  */
    303 
    304 void Curl_convert_close(struct Curl_easy *data)
    305 {
    306 #ifdef HAVE_ICONV
    307   /* close iconv conversion descriptors */
    308   if(data->inbound_cd != (iconv_t)-1) {
    309     iconv_close(data->inbound_cd);
    310   }
    311   if(data->outbound_cd != (iconv_t)-1) {
    312     iconv_close(data->outbound_cd);
    313   }
    314   if(data->utf8_cd != (iconv_t)-1) {
    315     iconv_close(data->utf8_cd);
    316   }
    317 #else
    318   (void)data;
    319 #endif /* HAVE_ICONV */
    320 }
    321 
    322 #endif /* CURL_DOES_CONVERSIONS */
    323