Home | History | Annotate | Download | only in lib
      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) 1998 - 2014, 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->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     char *input_ptr, *output_ptr;
    100     size_t in_bytes, out_bytes, rc;
    101     int error;
    102 
    103     /* open an iconv conversion descriptor if necessary */
    104     if(data->outbound_cd == (iconv_t)-1) {
    105       data->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
    106                                      CURL_ICONV_CODESET_OF_HOST);
    107       if(data->outbound_cd == (iconv_t)-1) {
    108         error = ERRNO;
    109         failf(data,
    110               "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
    111               CURL_ICONV_CODESET_OF_NETWORK,
    112               CURL_ICONV_CODESET_OF_HOST,
    113               error, strerror(error));
    114         return CURLE_CONV_FAILED;
    115       }
    116     }
    117     /* call iconv */
    118     input_ptr = output_ptr = buffer;
    119     in_bytes = out_bytes = length;
    120     rc = iconv(data->outbound_cd, (const char**)&input_ptr, &in_bytes,
    121                &output_ptr, &out_bytes);
    122     if((rc == ICONV_ERROR) || (in_bytes != 0)) {
    123       error = ERRNO;
    124       failf(data,
    125             "The Curl_convert_to_network iconv call failed with errno %i: %s",
    126             error, strerror(error));
    127       return CURLE_CONV_FAILED;
    128     }
    129 #else
    130     failf(data, "CURLOPT_CONV_TO_NETWORK_FUNCTION callback required");
    131     return CURLE_CONV_REQD;
    132 #endif /* HAVE_ICONV */
    133   }
    134 
    135   return CURLE_OK;
    136 }
    137 
    138 /*
    139  * Curl_convert_from_network() is an internal function for performing ASCII
    140  * conversions on non-ASCII platforms. It convers the buffer _in place_.
    141  */
    142 CURLcode Curl_convert_from_network(struct Curl_easy *data,
    143                                    char *buffer, size_t length)
    144 {
    145   if(data->set.convfromnetwork) {
    146     /* use translation callback */
    147     CURLcode result = data->set.convfromnetwork(buffer, length);
    148     if(result) {
    149       failf(data,
    150             "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback returned %d: %s",
    151             (int)result, curl_easy_strerror(result));
    152     }
    153 
    154     return result;
    155   }
    156   else {
    157 #ifdef HAVE_ICONV
    158     /* do the translation ourselves */
    159     char *input_ptr, *output_ptr;
    160     size_t in_bytes, out_bytes, rc;
    161     int error;
    162 
    163     /* open an iconv conversion descriptor if necessary */
    164     if(data->inbound_cd == (iconv_t)-1) {
    165       data->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
    166                                     CURL_ICONV_CODESET_OF_NETWORK);
    167       if(data->inbound_cd == (iconv_t)-1) {
    168         error = ERRNO;
    169         failf(data,
    170               "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
    171               CURL_ICONV_CODESET_OF_HOST,
    172               CURL_ICONV_CODESET_OF_NETWORK,
    173               error, strerror(error));
    174         return CURLE_CONV_FAILED;
    175       }
    176     }
    177     /* call iconv */
    178     input_ptr = output_ptr = buffer;
    179     in_bytes = out_bytes = length;
    180     rc = iconv(data->inbound_cd, (const char **)&input_ptr, &in_bytes,
    181                &output_ptr, &out_bytes);
    182     if((rc == ICONV_ERROR) || (in_bytes != 0)) {
    183       error = ERRNO;
    184       failf(data,
    185             "Curl_convert_from_network iconv call failed with errno %i: %s",
    186             error, strerror(error));
    187       return CURLE_CONV_FAILED;
    188     }
    189 #else
    190     failf(data, "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback required");
    191     return CURLE_CONV_REQD;
    192 #endif /* HAVE_ICONV */
    193   }
    194 
    195   return CURLE_OK;
    196 }
    197 
    198 /*
    199  * Curl_convert_from_utf8() is an internal function for performing UTF-8
    200  * conversions on non-ASCII platforms.
    201  */
    202 CURLcode Curl_convert_from_utf8(struct Curl_easy *data,
    203                                 char *buffer, size_t length)
    204 {
    205   if(data->set.convfromutf8) {
    206     /* use translation callback */
    207     CURLcode result = data->set.convfromutf8(buffer, length);
    208     if(result) {
    209       failf(data,
    210             "CURLOPT_CONV_FROM_UTF8_FUNCTION callback returned %d: %s",
    211             (int)result, curl_easy_strerror(result));
    212     }
    213 
    214     return result;
    215   }
    216   else {
    217 #ifdef HAVE_ICONV
    218     /* do the translation ourselves */
    219     const char *input_ptr;
    220     char *output_ptr;
    221     size_t in_bytes, out_bytes, rc;
    222     int error;
    223 
    224     /* open an iconv conversion descriptor if necessary */
    225     if(data->utf8_cd == (iconv_t)-1) {
    226       data->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
    227                                  CURL_ICONV_CODESET_FOR_UTF8);
    228       if(data->utf8_cd == (iconv_t)-1) {
    229         error = ERRNO;
    230         failf(data,
    231               "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
    232               CURL_ICONV_CODESET_OF_HOST,
    233               CURL_ICONV_CODESET_FOR_UTF8,
    234               error, strerror(error));
    235         return CURLE_CONV_FAILED;
    236       }
    237     }
    238     /* call iconv */
    239     input_ptr = output_ptr = buffer;
    240     in_bytes = out_bytes = length;
    241     rc = iconv(data->utf8_cd, &input_ptr, &in_bytes,
    242                &output_ptr, &out_bytes);
    243     if((rc == ICONV_ERROR) || (in_bytes != 0)) {
    244       error = ERRNO;
    245       failf(data,
    246             "The Curl_convert_from_utf8 iconv call failed with errno %i: %s",
    247             error, strerror(error));
    248       return CURLE_CONV_FAILED;
    249     }
    250     if(output_ptr < input_ptr) {
    251       /* null terminate the now shorter output string */
    252       *output_ptr = 0x00;
    253     }
    254 #else
    255     failf(data, "CURLOPT_CONV_FROM_UTF8_FUNCTION callback required");
    256     return CURLE_CONV_REQD;
    257 #endif /* HAVE_ICONV */
    258   }
    259 
    260   return CURLE_OK;
    261 }
    262 
    263 /*
    264  * Init conversion stuff for a Curl_easy
    265  */
    266 void Curl_convert_init(struct Curl_easy *data)
    267 {
    268 #if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
    269   /* conversion descriptors for iconv calls */
    270   data->outbound_cd = (iconv_t)-1;
    271   data->inbound_cd  = (iconv_t)-1;
    272   data->utf8_cd     = (iconv_t)-1;
    273 #else
    274   (void)data;
    275 #endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */
    276 }
    277 
    278 /*
    279  * Setup conversion stuff for a Curl_easy
    280  */
    281 void Curl_convert_setup(struct Curl_easy *data)
    282 {
    283   data->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
    284                                 CURL_ICONV_CODESET_OF_NETWORK);
    285   data->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
    286                                  CURL_ICONV_CODESET_OF_HOST);
    287   data->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
    288                              CURL_ICONV_CODESET_FOR_UTF8);
    289 }
    290 
    291 /*
    292  * Close conversion stuff for a Curl_easy
    293  */
    294 
    295 void Curl_convert_close(struct Curl_easy *data)
    296 {
    297 #ifdef HAVE_ICONV
    298   /* close iconv conversion descriptors */
    299   if(data->inbound_cd != (iconv_t)-1) {
    300     iconv_close(data->inbound_cd);
    301   }
    302   if(data->outbound_cd != (iconv_t)-1) {
    303     iconv_close(data->outbound_cd);
    304   }
    305   if(data->utf8_cd != (iconv_t)-1) {
    306     iconv_close(data->utf8_cd);
    307   }
    308 #else
    309   (void)data;
    310 #endif /* HAVE_ICONV */
    311 }
    312 
    313 /*
    314  * Curl_convert_form() is used from http.c, this converts any form items that
    315    need to be sent in the network encoding.  Returns CURLE_OK on success.
    316  */
    317 CURLcode Curl_convert_form(struct Curl_easy *data, struct FormData *form)
    318 {
    319   CURLcode result;
    320 
    321   if(!data)
    322     return CURLE_BAD_FUNCTION_ARGUMENT;
    323 
    324   while(form) {
    325     if(form->type == FORM_DATA) {
    326       result = Curl_convert_to_network(data, form->line, form->length);
    327       /* Curl_convert_to_network calls failf if unsuccessful */
    328       if(result)
    329         return result;
    330     }
    331 
    332     form = form->next;
    333   }
    334 
    335   return CURLE_OK;
    336 }
    337 
    338 #endif /* CURL_DOES_CONVERSIONS */
    339