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