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