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