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