1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2014, 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 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 */
Curl_convert_clone(struct Curl_easy * data,const char * indata,size_t insize,char ** outbuf)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 */
Curl_convert_to_network(struct Curl_easy * data,char * buffer,size_t length)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 */
Curl_convert_from_network(struct Curl_easy * data,char * buffer,size_t length)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 */
Curl_convert_from_utf8(struct Curl_easy * data,char * buffer,size_t length)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 */
Curl_convert_init(struct Curl_easy * data)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 */
Curl_convert_setup(struct Curl_easy * data)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
Curl_convert_close(struct Curl_easy * data)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 */
Curl_convert_form(struct Curl_easy * data,struct FormData * form)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