set_debugfunction: correctly allocate Curl.t
[ocurl.git] / curl-helper.c
blob7db5f80b4086999f6e71675c6fc29914ba1c06dc
1 /***
2 *** curl-helper.c
3 ***
4 *** Copyright (c) 2003-2008, Lars Nilsson, <lars@quantumchamaeleon.com>
5 *** Copyright (c) 2009, ygrek, <ygrek@autistici.org>
6 ***/
8 #include <stdio.h>
9 #include <string.h>
10 #include <stdlib.h>
11 #include <stdarg.h>
12 #include <caml/config.h>
13 #ifdef HAS_UNISTD
14 #include <unistd.h>
15 #endif
16 /* suppress false gcc warning on seekFunction */
17 #define CURL_DISABLE_TYPECHECK
18 #include <curl/curl.h>
20 #ifndef CAML_NAME_SPACE
21 #define CAML_NAME_SPACE
22 #endif
23 #include <caml/alloc.h>
24 #include <caml/memory.h>
25 #include <caml/mlvalues.h>
26 #include <caml/callback.h>
27 #include <caml/fail.h>
28 #include <caml/unixsupport.h>
29 #include <caml/custom.h>
30 #include <caml/threads.h>
32 #ifndef CAMLdrop
33 #define CAMLdrop caml_local_roots = caml__frame
34 #endif
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #else
39 #pragma message("No config file given.")
40 #endif
42 #ifdef __cplusplus
43 extern "C" {
44 #endif
46 #define Val_none Val_int(0)
48 static __inline value
49 Val_some( value v )
51 CAMLparam1( v );
52 CAMLlocal1( some );
53 some = caml_alloc(1, 0);
54 Store_field( some, 0, v );
55 CAMLreturn( some );
58 static value Val_pair(value v1, value v2)
60 CAMLparam2(v1,v2);
61 CAMLlocal1(pair);
62 pair = caml_alloc_small(2,0);
63 Field(pair,0) = v1;
64 Field(pair,1) = v2;
65 CAMLreturn(pair);
68 static value Val_cons(value list, value v) { return Val_pair(v,list); }
70 typedef struct Connection Connection;
71 typedef struct ConnectionList ConnectionList;
73 #define Connection_val(v) (*(Connection**)Data_custom_val(v))
75 typedef enum OcamlValues
77 Ocaml_WRITEFUNCTION,
78 Ocaml_READFUNCTION,
79 Ocaml_ERRORBUFFER,
80 Ocaml_POSTFIELDS,
81 Ocaml_HTTPHEADER,
82 Ocaml_HTTPPOST,
83 Ocaml_QUOTE,
84 Ocaml_POSTQUOTE,
85 Ocaml_HEADERFUNCTION,
86 Ocaml_PROGRESSFUNCTION,
87 Ocaml_DEBUGFUNCTION,
88 Ocaml_HTTP200ALIASES,
89 Ocaml_IOCTLFUNCTION,
90 Ocaml_SEEKFUNCTION,
91 Ocaml_OPENSOCKETFUNCTION,
93 Ocaml_URL,
94 Ocaml_PROXY,
95 Ocaml_USERPWD,
96 Ocaml_PROXYUSERPWD,
97 Ocaml_RANGE,
98 Ocaml_REFERER,
99 Ocaml_USERAGENT,
100 Ocaml_FTPPORT,
101 Ocaml_COOKIE,
102 Ocaml_HTTPPOSTSTRINGS,
103 Ocaml_SSLCERT,
104 Ocaml_SSLCERTTYPE,
105 Ocaml_SSLCERTPASSWD,
106 Ocaml_SSLKEY,
107 Ocaml_SSLKEYTYPE,
108 Ocaml_SSLKEYPASSWD,
109 Ocaml_SSLENGINE,
110 Ocaml_COOKIEFILE,
111 Ocaml_CUSTOMREQUEST,
112 Ocaml_INTERFACE,
113 Ocaml_CAINFO,
114 Ocaml_CAPATH,
115 Ocaml_RANDOM_FILE,
116 Ocaml_EGDSOCKET,
117 Ocaml_COOKIEJAR,
118 Ocaml_SSL_CIPHER_LIST,
119 Ocaml_PRIVATE,
120 Ocaml_NETRC_FILE,
121 Ocaml_FTP_ACCOUNT,
122 Ocaml_COOKIELIST,
123 Ocaml_FTP_ALTERNATIVE_TO_USER,
124 Ocaml_SSH_PUBLIC_KEYFILE,
125 Ocaml_SSH_PRIVATE_KEYFILE,
126 Ocaml_SSH_HOST_PUBLIC_KEY_MD5,
127 Ocaml_COPYPOSTFIELDS,
128 Ocaml_DNS_SERVERS,
129 Ocaml_MAIL_FROM,
130 Ocaml_MAIL_RCPT,
131 Ocaml_RESOLVE,
133 /* Not used, last for size */
134 OcamlValuesSize
135 } OcamlValue;
137 struct Connection
139 CURL *handle;
141 value ocamlValues;
143 size_t refcount; /* number of references to this structure */
145 char *curl_URL;
146 char *curl_PROXY;
147 char *curl_USERPWD;
148 char *curl_PROXYUSERPWD;
149 char *curl_RANGE;
150 char *curl_ERRORBUFFER;
151 char *curl_POSTFIELDS;
152 int curl_POSTFIELDSIZE;
153 char *curl_REFERER;
154 char *curl_USERAGENT;
155 char *curl_FTPPORT;
156 char *curl_COOKIE;
157 struct curl_slist *curl_HTTPHEADER;
158 struct curl_slist *httpPostBuffers;
159 struct curl_httppost *httpPostFirst;
160 struct curl_httppost *httpPostLast;
161 struct curl_slist *curl_RESOLVE;
162 char *curl_SSLCERT;
163 char *curl_SSLCERTTYPE;
164 char *curl_SSLCERTPASSWD;
165 char *curl_SSLKEY;
166 char *curl_SSLKEYTYPE;
167 char *curl_SSLKEYPASSWD;
168 char *curl_SSLENGINE;
169 struct curl_slist *curl_QUOTE;
170 struct curl_slist *curl_POSTQUOTE;
171 char *curl_COOKIEFILE;
172 char *curl_CUSTOMREQUEST;
173 char *curl_INTERFACE;
174 char *curl_CAINFO;
175 char *curl_CAPATH;
176 char *curl_RANDOM_FILE;
177 char *curl_EGDSOCKET;
178 char *curl_COOKIEJAR;
179 char *curl_SSL_CIPHER_LIST;
180 struct curl_slist *curl_HTTP200ALIASES;
181 char *curl_NETRC_FILE;
182 char *curl_FTP_ACCOUNT;
183 char *curl_COOKIELIST;
184 char *curl_FTP_ALTERNATIVE_TO_USER;
185 char *curl_SSH_PUBLIC_KEYFILE;
186 char *curl_SSH_PRIVATE_KEYFILE;
187 char *curl_SSH_HOST_PUBLIC_KEY_MD5;
188 char *curl_COPYPOSTFIELDS;
189 char *curl_DNS_SERVERS;
190 char *curl_MAIL_FROM;
191 struct curl_slist *curl_MAIL_RCPT;
194 typedef struct CURLErrorMapping CURLErrorMapping;
196 struct CURLErrorMapping
198 char *name;
199 CURLcode error;
202 CURLErrorMapping errorMap[] =
204 {"CURLE_OK", CURLE_OK},
205 #if HAVE_DECL_CURLE_UNSUPPORTED_PROTOCOL
206 {"CURLE_UNSUPPORTED_PROTOCOL", CURLE_UNSUPPORTED_PROTOCOL},
207 #else
208 {"CURLE_UNSUPPORTED_PROTOCOL", -1},
209 #endif
210 #if HAVE_DECL_CURLE_FAILED_INIT
211 {"CURLE_FAILED_INIT", CURLE_FAILED_INIT},
212 #else
213 {"CURLE_FAILED_INIT", -1},
214 #endif
215 #if HAVE_DECL_CURLE_URL_MALFORMAT
216 {"CURLE_URL_MALFORMAT", CURLE_URL_MALFORMAT},
217 #else
218 {"CURLE_URL_MALFORMAT", -1},
219 #endif
220 #if HAVE_DECL_CURLE_URL_MALFORMAT_USER
221 {"CURLE_URL_MALFORMAT_USER", CURLE_URL_MALFORMAT_USER},
222 #else
223 {"CURLE_URL_MALFORMAT_USER", -1},
224 #endif
225 #if HAVE_DECL_CURLE_COULDNT_RESOLVE_PROXY
226 {"CURLE_COULDNT_RESOLVE_PROXY", CURLE_COULDNT_RESOLVE_PROXY},
227 #else
228 {"CURLE_COULDNT_RESOLVE_PROXY", -1},
229 #endif
230 #if HAVE_DECL_CURLE_COULDNT_RESOLVE_HOST
231 {"CURLE_COULDNT_RESOLVE_HOST", CURLE_COULDNT_RESOLVE_HOST},
232 #else
233 {"CURLE_COULDNT_RESOLVE_HOST", -1},
234 #endif
235 #if HAVE_DECL_CURLE_COULDNT_CONNECT
236 {"CURLE_COULDNT_CONNECT", CURLE_COULDNT_CONNECT},
237 #else
238 {"CURLE_COULDNT_CONNECT", -1},
239 #endif
240 #if HAVE_DECL_CURLE_FTP_WEIRD_SERVER_REPLY
241 {"CURLE_FTP_WEIRD_SERVER_REPLY", CURLE_FTP_WEIRD_SERVER_REPLY},
242 #else
243 {"CURLE_FTP_WEIRD_SERVER_REPLY", -1},
244 #endif
245 #if HAVE_DECL_CURLE_FTP_ACCESS_DENIED
246 {"CURLE_FTP_ACCESS_DENIED", CURLE_FTP_ACCESS_DENIED},
247 #else
248 {"CURLE_FTP_ACCESS_DENIED", -1},
249 #endif
250 #if HAVE_DECL_CURLE_FTP_USER_PASSWORD_INCORRECT
251 {"CURLE_FTP_USER_PASSWORD_INCORRECT", CURLE_FTP_USER_PASSWORD_INCORRECT},
252 #else
253 {"CURLE_FTP_USER_PASSWORD_INCORRECT", -1},
254 #endif
255 #if HAVE_DECL_CURLE_FTP_WEIRD_PASS_REPLY
256 {"CURLE_FTP_WEIRD_PASS_REPLY", CURLE_FTP_WEIRD_PASS_REPLY},
257 #else
258 {"CURLE_FTP_WEIRD_PASS_REPLY", -1},
259 #endif
260 #if HAVE_DECL_CURLE_FTP_WEIRD_USER_REPLY
261 {"CURLE_FTP_WEIRD_USER_REPLY", CURLE_FTP_WEIRD_USER_REPLY},
262 #else
263 {"CURLE_FTP_WEIRD_USER_REPLY", -1},
264 #endif
265 #if HAVE_DECL_CURLE_FTP_WEIRD_PASV_REPLY
266 {"CURLE_FTP_WEIRD_PASV_REPLY", CURLE_FTP_WEIRD_PASV_REPLY},
267 #else
268 {"CURLE_FTP_WEIRD_PASV_REPLY", -1},
269 #endif
270 #if HAVE_DECL_CURLE_FTP_WEIRD_227_FORMAT
271 {"CURLE_FTP_WEIRD_227_FORMAT", CURLE_FTP_WEIRD_227_FORMAT},
272 #else
273 {"CURLE_FTP_WEIRD_227_FORMAT", -1},
274 #endif
275 #if HAVE_DECL_CURLE_FTP_CANT_GET_HOST
276 {"CURLE_FTP_CANT_GET_HOST", CURLE_FTP_CANT_GET_HOST},
277 #else
278 {"CURLE_FTP_CANT_GET_HOST", -1},
279 #endif
280 #if HAVE_DECL_CURLE_FTP_CANT_RECONNECT
281 {"CURLE_FTP_CANT_RECONNECT", CURLE_FTP_CANT_RECONNECT},
282 #else
283 {"CURLE_FTP_CANT_RECONNECT", -1},
284 #endif
285 #if HAVE_DECL_CURLE_FTP_COULDNT_SET_BINARY
286 {"CURLE_FTP_COULDNT_SET_BINARY", CURLE_FTP_COULDNT_SET_BINARY},
287 #else
288 {"CURLE_FTP_COULDNT_SET_BINARY", -1},
289 #endif
290 #if HAVE_DECL_CURLE_PARTIAL_FILE
291 {"CURLE_PARTIAL_FILE", CURLE_PARTIAL_FILE},
292 #else
293 {"CURLE_PARTIAL_FILE", -1},
294 #endif
295 #if HAVE_DECL_CURLE_FTP_COULDNT_RETR_FILE
296 {"CURLE_FTP_COULDNT_RETR_FILE", CURLE_FTP_COULDNT_RETR_FILE},
297 #else
298 {"CURLE_FTP_COULDNT_RETR_FILE", -1},
299 #endif
300 #if HAVE_DECL_CURLE_FTP_WRITE_ERROR
301 {"CURLE_FTP_WRITE_ERROR", CURLE_FTP_WRITE_ERROR},
302 #else
303 {"CURLE_FTP_WRITE_ERROR", -1},
304 #endif
305 #if HAVE_DECL_CURLE_FTP_QUOTE_ERROR
306 {"CURLE_FTP_QUOTE_ERROR", CURLE_FTP_QUOTE_ERROR},
307 #else
308 {"CURLE_FTP_QUOTE_ERROR", -1},
309 #endif
310 #if HAVE_DECL_CURLE_HTTP_RETURNED_ERROR
311 {"CURLE_HTTP_RETURNED_ERROR", CURLE_HTTP_RETURNED_ERROR},
312 #else
313 {"CURLE_HTTP_RETURNED_ERROR", -1},
314 #endif
315 #if HAVE_DECL_CURLE_WRITE_ERROR
316 {"CURLE_WRITE_ERROR", CURLE_WRITE_ERROR},
317 #else
318 {"CURLE_WRITE_ERROR", -1},
319 #endif
320 #if HAVE_DECL_CURLE_MALFORMAT_USER
321 {"CURLE_MALFORMAT_USER", CURLE_MALFORMAT_USER},
322 #else
323 {"CURLE_MALFORMAT_USER", -1},
324 #endif
325 #if HAVE_DECL_CURLE_FTP_COULDNT_STOR_FILE
326 {"CURLE_FTP_COULDNT_STOR_FILE", CURLE_FTP_COULDNT_STOR_FILE},
327 #else
328 {"CURLE_FTP_COULDNT_STOR_FILE", -1},
329 #endif
330 #if HAVE_DECL_CURLE_READ_ERROR
331 {"CURLE_READ_ERROR", CURLE_READ_ERROR},
332 #else
333 {"CURLE_READ_ERROR", -1},
334 #endif
335 #if HAVE_DECL_CURLE_OUT_OF_MEMORY
336 {"CURLE_OUT_OF_MEMORY", CURLE_OUT_OF_MEMORY},
337 #else
338 {"CURLE_OUT_OF_MEMORY", -1},
339 #endif
340 #if HAVE_DECL_CURLE_OPERATION_TIMEOUTED
341 {"CURLE_OPERATION_TIMEOUTED", CURLE_OPERATION_TIMEOUTED},
342 #else
343 {"CURLE_OPERATION_TIMEOUTED", -1},
344 #endif
345 #if HAVE_DECL_CURLE_FTP_COULDNT_SET_ASCII
346 {"CURLE_FTP_COULDNT_SET_ASCII", CURLE_FTP_COULDNT_SET_ASCII},
347 #else
348 {"CURLE_FTP_COULDNT_SET_ASCII", -1},
349 #endif
350 #if HAVE_DECL_CURLE_FTP_PORT_FAILED
351 {"CURLE_FTP_PORT_FAILED", CURLE_FTP_PORT_FAILED},
352 #else
353 {"CURLE_FTP_PORT_FAILED", -1},
354 #endif
355 #if HAVE_DECL_CURLE_FTP_COULDNT_USE_REST
356 {"CURLE_FTP_COULDNT_USE_REST", CURLE_FTP_COULDNT_USE_REST},
357 #else
358 {"CURLE_FTP_COULDNT_USE_REST", -1},
359 #endif
360 #if HAVE_DECL_CURLE_FTP_COULDNT_GET_SIZE
361 {"CURLE_FTP_COULDNT_GET_SIZE", CURLE_FTP_COULDNT_GET_SIZE},
362 #else
363 {"CURLE_FTP_COULDNT_GET_SIZE", -1},
364 #endif
365 #if HAVE_DECL_CURLE_HTTP_RANGE_ERROR
366 {"CURLE_HTTP_RANGE_ERROR", CURLE_HTTP_RANGE_ERROR},
367 #else
368 {"CURLE_HTTP_RANGE_ERROR", -1},
369 #endif
370 #if HAVE_DECL_CURLE_HTTP_POST_ERROR
371 {"CURLE_HTTP_POST_ERROR", CURLE_HTTP_POST_ERROR},
372 #else
373 {"CURLE_HTTP_POST_ERROR", -1},
374 #endif
375 #if HAVE_DECL_CURLE_SSL_CONNECT_ERROR
376 {"CURLE_SSL_CONNECT_ERROR", CURLE_SSL_CONNECT_ERROR},
377 #else
378 {"CURLE_SSL_CONNECT_ERROR", -1},
379 #endif
380 #if HAVE_DECL_CURLE_BAD_DOWNLOAD_RESUME
381 {"CURLE_BAD_DOWNLOAD_RESUME", CURLE_BAD_DOWNLOAD_RESUME},
382 #else
383 {"CURLE_BAD_DOWNLOAD_RESUME", -1},
384 #endif
385 #if HAVE_DECL_CURLE_FILE_COULDNT_READ_FILE
386 {"CURLE_FILE_COULDNT_READ_FILE", CURLE_FILE_COULDNT_READ_FILE},
387 #else
388 {"CURLE_FILE_COULDNT_READ_FILE", -1},
389 #endif
390 #if HAVE_DECL_CURLE_LDAP_CANNOT_BIND
391 {"CURLE_LDAP_CANNOT_BIND", CURLE_LDAP_CANNOT_BIND},
392 #else
393 {"CURLE_LDAP_CANNOT_BIND", -1},
394 #endif
395 #if HAVE_DECL_CURLE_LDAP_SEARCH_FAILED
396 {"CURLE_LDAP_SEARCH_FAILED", CURLE_LDAP_SEARCH_FAILED},
397 #else
398 {"CURLE_LDAP_SEARCH_FAILED", -1},
399 #endif
400 #if HAVE_DECL_CURLE_LIBRARY_NOT_FOUND
401 {"CURLE_LIBRARY_NOT_FOUND", CURLE_LIBRARY_NOT_FOUND},
402 #else
403 {"CURLE_LIBRARY_NOT_FOUND", -1},
404 #endif
405 #if HAVE_DECL_CURLE_FUNCTION_NOT_FOUND
406 {"CURLE_FUNCTION_NOT_FOUND", CURLE_FUNCTION_NOT_FOUND},
407 #else
408 {"CURLE_FUNCTION_NOT_FOUND", -1},
409 #endif
410 #if HAVE_DECL_CURLE_ABORTED_BY_CALLBACK
411 {"CURLE_ABORTED_BY_CALLBACK", CURLE_ABORTED_BY_CALLBACK},
412 #else
413 {"CURLE_ABORTED_BY_CALLBACK", -1},
414 #endif
415 #if HAVE_DECL_CURLE_BAD_FUNCTION_ARGUMENT
416 {"CURLE_BAD_FUNCTION_ARGUMENT", CURLE_BAD_FUNCTION_ARGUMENT},
417 #else
418 {"CURLE_BAD_FUNCTION_ARGUMENT", -1},
419 #endif
420 #if HAVE_DECL_CURLE_BAD_CALLING_ORDER
421 {"CURLE_BAD_CALLING_ORDER", CURLE_BAD_CALLING_ORDER},
422 #else
423 {"CURLE_BAD_CALLING_ORDER", -1},
424 #endif
425 #if HAVE_DECL_CURLE_INTERFACE_FAILED
426 {"CURLE_INTERFACE_FAILED", CURLE_INTERFACE_FAILED},
427 #else
428 {"CURLE_INTERFACE_FAILED", -1},
429 #endif
430 #if HAVE_DECL_CURLE_BAD_PASSWORD_ENTERED
431 {"CURLE_BAD_PASSWORD_ENTERED", CURLE_BAD_PASSWORD_ENTERED},
432 #else
433 {"CURLE_BAD_PASSWORD_ENTERED", -1},
434 #endif
435 #if HAVE_DECL_CURLE_TOO_MANY_REDIRECTS
436 {"CURLE_TOO_MANY_REDIRECTS", CURLE_TOO_MANY_REDIRECTS},
437 #else
438 {"CURLE_TOO_MANY_REDIRECTS", -1},
439 #endif
440 #if HAVE_DECL_CURLE_UNKNOWN_TELNET_OPTION
441 {"CURLE_UNKNOWN_TELNET_OPTION", CURLE_UNKNOWN_TELNET_OPTION},
442 #else
443 {"CURLE_UNKNOWN_TELNET_OPTION", -1},
444 #endif
445 #if HAVE_DECL_CURLE_TELNET_OPTION_SYNTAX
446 {"CURLE_TELNET_OPTION_SYNTAX", CURLE_TELNET_OPTION_SYNTAX},
447 #else
448 {"CURLE_TELNET_OPTION_SYNTAX", -1},
449 #endif
450 #if HAVE_DECL_CURLE_SSL_PEER_CERTIFICATE
451 {"CURLE_SSL_PEER_CERTIFICATE", CURLE_SSL_PEER_CERTIFICATE},
452 #else
453 {"CURLE_SSL_PEER_CERTIFICATE", -1},
454 #endif
455 #if HAVE_DECL_CURLE_GOT_NOTHING
456 {"CURLE_GOT_NOTHING", CURLE_GOT_NOTHING},
457 #else
458 {"CURLE_GOT_NOTHING", -1},
459 #endif
460 #if HAVE_DECL_CURLE_SSL_ENGINE_NOTFOUND
461 {"CURLE_SSL_ENGINE_NOTFOUND", CURLE_SSL_ENGINE_NOTFOUND},
462 #else
463 {"CURLE_SSL_ENGINE_NOTFOUND", -1},
464 #endif
465 #if HAVE_DECL_CURLE_SSL_ENGINE_SETFAILED
466 {"CURLE_SSL_ENGINE_SETFAILED", CURLE_SSL_ENGINE_SETFAILED},
467 #else
468 {"CURLE_SSL_ENGINE_SETFAILED", -1},
469 #endif
470 #if HAVE_DECL_CURLE_SEND_ERROR
471 {"CURLE_SEND_ERROR", CURLE_SEND_ERROR},
472 #else
473 {"CURLE_SEND_ERROR", -1},
474 #endif
475 #if HAVE_DECL_CURLE_RECV_ERROR
476 {"CURLE_RECV_ERROR", CURLE_RECV_ERROR},
477 #else
478 {"CURLE_RECV_ERROR", -1},
479 #endif
480 #if HAVE_DECL_CURLE_SHARE_IN_USE
481 {"CURLE_SHARE_IN_USE", CURLE_SHARE_IN_USE},
482 #else
483 {"CURLE_SHARE_IN_USE", -1},
484 #endif
485 #if HAVE_DECL_CURLE_SSL_CERTPROBLEM
486 {"CURLE_SSL_CERTPROBLEM", CURLE_SSL_CERTPROBLEM},
487 #else
488 {"CURLE_SSL_CERTPROBLEM", -1},
489 #endif
490 #if HAVE_DECL_CURLE_SSL_CIPHER
491 {"CURLE_SSL_CIPHER", CURLE_SSL_CIPHER},
492 #else
493 {"CURLE_SSL_CIPHER", -1},
494 #endif
495 #if HAVE_DECL_CURLE_SSL_CACERT
496 {"CURLE_SSL_CACERT", CURLE_SSL_CACERT},
497 #else
498 {"CURLE_SSL_CACERT", -1},
499 #endif
500 #if HAVE_DECL_CURLE_BAD_CONTENT_ENCODING
501 {"CURLE_BAD_CONTENT_ENCODING", CURLE_BAD_CONTENT_ENCODING},
502 #else
503 {"CURLE_BAD_CONTENT_ENCODING", -1},
504 #endif
505 #if HAVE_DECL_CURLE_LDAP_INVALID_URL
506 {"CURLE_LDAP_INVALID_URL", CURLE_LDAP_INVALID_URL},
507 #else
508 {"CURLE_LDAP_INVALID_URL", -1},
509 #endif
510 #if HAVE_DECL_CURLE_FILESIZE_EXCEEDED
511 {"CURLE_FILESIZE_EXCEEDED", CURLE_FILESIZE_EXCEEDED},
512 #else
513 {"CURLE_FILESIZE_EXCEEDED", -1},
514 #endif
515 #if HAVE_DECL_CURLE_FTP_SSL_FAILED
516 {"CURLE_FTP_SSL_FAILED", CURLE_FTP_SSL_FAILED},
517 #else
518 {"CURLE_FTP_SSL_FAILED", -1},
519 #endif
520 #if HAVE_DECL_CURLE_SEND_FAIL_REWIND
521 {"CURLE_SEND_FAIL_REWIND", CURLE_SEND_FAIL_REWIND},
522 #else
523 {"CURLE_SEND_FAIL_REWIND", -1},
524 #endif
525 #if HAVE_DECL_CURLE_SSL_ENGINE_INITFAILED
526 {"CURLE_SSL_ENGINE_INITFAILED", CURLE_SSL_ENGINE_INITFAILED},
527 #else
528 {"CURLE_SSL_ENGINE_INITFAILED", -1},
529 #endif
530 #if HAVE_DECL_CURLE_LOGIN_DENIED
531 {"CURLE_LOGIN_DENIED", CURLE_LOGIN_DENIED},
532 #else
533 {"CURLE_LOGIN_DENIED", -1},
534 #endif
535 #if HAVE_DECL_CURLE_TFTP_NOTFOUND
536 {"CURLE_TFTP_NOTFOUND", CURLE_TFTP_NOTFOUND},
537 #else
538 {"CURLE_TFTP_NOTFOUND", -1},
539 #endif
540 #if HAVE_DECL_CURLE_TFTP_PERM
541 {"CURLE_TFTP_PERM", CURLE_TFTP_PERM},
542 #else
543 {"CURLE_TFTP_PERM", -1},
544 #endif
545 #if HAVE_DECL_CURLE_REMOTE_DISK_FULL
546 {"CURLE_REMOTE_DISK_FULL", CURLE_REMOTE_DISK_FULL},
547 #else
548 {"CURLE_REMOTE_DISK_FULL", -1},
549 #endif
550 #if HAVE_DECL_CURLE_TFTP_ILLEGAL
551 {"CURLE_TFTP_ILLEGAL", CURLE_TFTP_ILLEGAL},
552 #else
553 {"CURLE_TFTP_ILLEGAL", -1},
554 #endif
555 #if HAVE_DECL_CURLE_TFTP_UNKNOWNID
556 {"CURLE_TFTP_UNKNOWNID", CURLE_TFTP_UNKNOWNID},
557 #else
558 {"CURLE_TFTP_UNKNOWNID", -1},
559 #endif
560 #if HAVE_DECL_CURLE_REMOTE_FILE_EXISTS
561 {"CURLE_REMOTE_FILE_EXISTS", CURLE_REMOTE_FILE_EXISTS},
562 #else
563 {"CURLE_REMOTE_FILE_EXISTS", -1},
564 #endif
565 #if HAVE_DECL_CURLE_TFTP_NOSUCHUSER
566 {"CURLE_TFTP_NOSUCHUSER", CURLE_TFTP_NOSUCHUSER},
567 #else
568 {"CURLE_TFTP_NOSUCHUSER", -1},
569 #endif
570 #if HAVE_DECL_CURLE_CONV_FAILED
571 {"CURLE_CONV_FAILED", CURLE_CONV_FAILED},
572 #else
573 {"CURLE_CONV_FAILED", -1},
574 #endif
575 #if HAVE_DECL_CURLE_CONV_REQD
576 {"CURLE_CONV_REQD", CURLE_CONV_REQD},
577 #else
578 {"CURLE_CONV_REQD", -1},
579 #endif
580 #if HAVE_DECL_CURLE_SSL_CACERT_BADFILE
581 {"CURLE_SSL_CACERT_BADFILE", CURLE_SSL_CACERT_BADFILE},
582 #else
583 {"CURLE_SSL_CACERT_BADFILE", -1},
584 #endif
585 #if HAVE_DECL_CURLE_REMOTE_FILE_NOT_FOUND
586 {"CURLE_REMOTE_FILE_NOT_FOUND", CURLE_REMOTE_FILE_NOT_FOUND},
587 #else
588 {"CURLE_REMOTE_FILE_NOT_FOUND", -1},
589 #endif
590 #if HAVE_DECL_CURLE_SSH
591 {"CURLE_SSH", CURLE_SSH},
592 #else
593 {"CURLE_SSH", -1},
594 #endif
595 #if HAVE_DECL_CURLE_SSL_SHUTDOWN_FAILED
596 {"CURLE_SSL_SHUTDOWN_FAILED", CURLE_SSL_SHUTDOWN_FAILED},
597 #else
598 {"CURLE_SSL_SHUTDOWN_FAILED", -1},
599 #endif
600 #if HAVE_DECL_CURLE_AGAIN
601 {"CURLE_AGAIN", CURLE_AGAIN},
602 #else
603 {"CURLE_AGAIN", -1},
604 #endif
605 {NULL, (CURLcode)0}
608 typedef struct CURLOptionMapping CURLOptionMapping;
610 struct CURLOptionMapping
612 void (*optionHandler)(Connection *, value);
613 char *name;
614 OcamlValue ocamlValue;
617 static char* strdup_ml(value v)
619 char* p = NULL;
620 p = (char*)malloc(caml_string_length(v)+1);
621 memcpy(p,String_val(v),caml_string_length(v)+1); // caml strings have terminating zero
622 return p;
625 static value ml_copy_string(char const* p, size_t size)
627 value v = caml_alloc_string(size);
628 memcpy(&Byte(v,0),p,size);
629 return v;
632 /* prepends to the beginning of list */
633 static struct curl_slist* curl_slist_prepend_ml(struct curl_slist* list, value v)
635 /* FIXME check NULLs */
636 struct curl_slist* new_item = (struct curl_slist*)malloc(sizeof(struct curl_slist));
638 new_item->next = list;
639 new_item->data = strdup_ml(v);
641 return new_item;
644 static void free_curl_slist(struct curl_slist *slist)
646 if (NULL == slist)
647 return;
649 curl_slist_free_all(slist);
652 static void raiseError(Connection *conn, CURLcode code)
654 CAMLparam0();
655 CAMLlocal1(exceptionData);
656 value *exception;
657 char *errorString = "Unknown Error";
658 int i;
660 for (i = 0; errorMap[i].name != NULL; i++)
662 if (errorMap[i].error == code)
664 errorString = errorMap[i].name;
665 break;
669 exceptionData = caml_alloc_tuple(3);
671 Store_field(exceptionData, 0, Val_int(code));
672 Store_field(exceptionData, 1, Val_int(code));
673 Store_field(exceptionData, 2, caml_copy_string(errorString));
675 if (conn != NULL && conn->curl_ERRORBUFFER != NULL)
677 Store_field(Field(conn->ocamlValues, Ocaml_ERRORBUFFER), 0, caml_copy_string(conn->curl_ERRORBUFFER));
680 exception = caml_named_value("CurlException");
682 if (exception == NULL)
683 caml_failwith("CurlException not registered");
685 caml_raise_with_arg(*exception, exceptionData);
687 CAMLreturn0;
690 static void resetOcamlValues(Connection* connection)
692 int i;
694 for (i = 0; i < OcamlValuesSize; i++)
695 Store_field(connection->ocamlValues, i, Val_unit);
698 static Connection* allocConnection(CURL* h)
700 Connection* connection = (Connection *)malloc(sizeof(Connection));
702 connection->ocamlValues = caml_alloc(OcamlValuesSize, 0);
703 resetOcamlValues(connection);
704 caml_register_global_root(&connection->ocamlValues);
706 connection->handle = h;
707 curl_easy_setopt(h, CURLOPT_PRIVATE, connection);
709 connection->refcount = 0;
711 connection->curl_URL = NULL;
712 connection->curl_PROXY = NULL;
713 connection->curl_USERPWD = NULL;
714 connection->curl_PROXYUSERPWD = NULL;
715 connection->curl_RANGE = NULL;
716 connection->curl_ERRORBUFFER = NULL;
717 connection->curl_POSTFIELDS = NULL;
718 connection->curl_POSTFIELDSIZE = -1;
719 connection->curl_REFERER = NULL;
720 connection->curl_USERAGENT = NULL;
721 connection->curl_FTPPORT = NULL;
722 connection->curl_COOKIE = NULL;
723 connection->curl_HTTPHEADER = NULL;
724 connection->httpPostBuffers = NULL;
725 connection->httpPostFirst = NULL;
726 connection->httpPostLast = NULL;
727 connection->curl_SSLCERT = NULL;
728 connection->curl_SSLCERTTYPE = NULL;
729 connection->curl_SSLCERTPASSWD = NULL;
730 connection->curl_SSLKEY = NULL;
731 connection->curl_SSLKEYTYPE = NULL;
732 connection->curl_SSLKEYPASSWD = NULL;
733 connection->curl_SSLENGINE = NULL;
734 connection->curl_QUOTE = NULL;
735 connection->curl_POSTQUOTE = NULL;
736 connection->curl_COOKIEFILE = NULL;
737 connection->curl_CUSTOMREQUEST = NULL;
738 connection->curl_INTERFACE = NULL;
739 connection->curl_CAINFO = NULL;
740 connection->curl_CAPATH = NULL;
741 connection->curl_RANDOM_FILE = NULL;
742 connection->curl_EGDSOCKET = NULL;
743 connection->curl_COOKIEJAR = NULL;
744 connection->curl_SSL_CIPHER_LIST = NULL;
745 connection->curl_HTTP200ALIASES = NULL;
746 connection->curl_NETRC_FILE = NULL;
747 connection->curl_FTP_ACCOUNT = NULL;
748 connection->curl_COOKIELIST = NULL;
749 connection->curl_FTP_ALTERNATIVE_TO_USER = NULL;
750 connection->curl_SSH_PUBLIC_KEYFILE = NULL;
751 connection->curl_SSH_PRIVATE_KEYFILE = NULL;
752 connection->curl_COPYPOSTFIELDS = NULL;
753 connection->curl_RESOLVE = NULL;
754 connection->curl_DNS_SERVERS = NULL;
755 connection->curl_MAIL_FROM = NULL;
756 connection->curl_MAIL_RCPT = NULL;
758 return connection;
761 static Connection *newConnection(void)
763 CURL* h;
765 caml_enter_blocking_section();
766 h = curl_easy_init();
767 caml_leave_blocking_section();
769 return allocConnection(h);
772 static void free_if(void* p) { if (NULL != p) free(p); }
774 static void removeConnection(Connection *connection, int finalization)
776 const char* fin_url = NULL;
778 if (!connection->handle)
780 return; /* already cleaned up */
783 if (finalization)
785 /* cannot engage OCaml runtime at finalization, just report leak */
786 if (CURLE_OK != curl_easy_getinfo(connection->handle, CURLINFO_EFFECTIVE_URL, &fin_url) || NULL == fin_url)
788 fin_url = "unknown";
790 fprintf(stderr,"Curl: handle %p leaked, conn %p, url %s\n", connection->handle, connection, fin_url);
791 fflush(stderr);
793 else
795 caml_enter_blocking_section();
796 curl_easy_cleanup(connection->handle);
797 caml_leave_blocking_section();
800 connection->handle = NULL;
802 caml_remove_global_root(&connection->ocamlValues);
804 free_if(connection->curl_URL);
805 free_if(connection->curl_PROXY);
806 free_if(connection->curl_USERPWD);
807 free_if(connection->curl_PROXYUSERPWD);
808 free_if(connection->curl_RANGE);
809 free_if(connection->curl_ERRORBUFFER);
810 free_if(connection->curl_POSTFIELDS);
811 free_if(connection->curl_REFERER);
812 free_if(connection->curl_USERAGENT);
813 free_if(connection->curl_FTPPORT);
814 free_if(connection->curl_COOKIE);
815 free_curl_slist(connection->curl_HTTPHEADER);
816 free_curl_slist(connection->httpPostBuffers);
817 if (connection->httpPostFirst != NULL)
818 curl_formfree(connection->httpPostFirst);
819 free_curl_slist(connection->curl_RESOLVE);
820 free_if(connection->curl_SSLCERT);
821 free_if(connection->curl_SSLCERTTYPE);
822 free_if(connection->curl_SSLCERTPASSWD);
823 free_if(connection->curl_SSLKEY);
824 free_if(connection->curl_SSLKEYTYPE);
825 free_if(connection->curl_SSLKEYPASSWD);
826 free_if(connection->curl_SSLENGINE);
827 free_curl_slist(connection->curl_QUOTE);
828 free_curl_slist(connection->curl_POSTQUOTE);
829 free_if(connection->curl_COOKIEFILE);
830 free_if(connection->curl_CUSTOMREQUEST);
831 free_if(connection->curl_INTERFACE);
832 free_if(connection->curl_CAINFO);
833 free_if(connection->curl_CAPATH);
834 free_if(connection->curl_RANDOM_FILE);
835 free_if(connection->curl_EGDSOCKET);
836 free_if(connection->curl_COOKIEJAR);
837 free_if(connection->curl_SSL_CIPHER_LIST);
838 free_curl_slist(connection->curl_HTTP200ALIASES);
839 free_if(connection->curl_NETRC_FILE);
840 free_if(connection->curl_FTP_ACCOUNT);
841 free_if(connection->curl_COOKIELIST);
842 free_if(connection->curl_FTP_ALTERNATIVE_TO_USER);
843 free_if(connection->curl_SSH_PUBLIC_KEYFILE);
844 free_if(connection->curl_SSH_PRIVATE_KEYFILE);
845 free_if(connection->curl_COPYPOSTFIELDS);
846 free_if(connection->curl_DNS_SERVERS);
847 free_if(connection->curl_MAIL_FROM);
848 free_curl_slist(connection->curl_MAIL_RCPT);
851 static Connection* getConnection(CURL* h)
853 Connection* p = NULL;
855 if (CURLE_OK != curl_easy_getinfo(h, CURLINFO_PRIVATE, &p) || NULL == p)
857 caml_failwith("Unknown handle");
860 return p;
863 #if 1
864 static void checkConnection(Connection * connection)
866 (void)connection;
868 #else
869 static void checkConnection(Connection *connection)
871 if (connection != getConnection(connection->handle))
873 caml_failwith("Invalid Connection");
876 #endif
878 void op_curl_easy_finalize(value v)
880 Connection* conn = Connection_val(v);
881 /* same connection may be referenced by several different
882 OCaml values, see e.g. caml_curl_multi_remove_finished */
883 conn->refcount--;
884 if (0 == conn->refcount)
886 removeConnection(conn, 1);
887 free(conn);
891 int op_curl_easy_compare(value v1, value v2)
893 size_t p1 = (size_t)Connection_val(v1);
894 size_t p2 = (size_t)Connection_val(v2);
895 return (p1 == p2 ? 0 : (p1 > p2 ? 1 : -1)); /* compare addresses */
898 intnat op_curl_easy_hash(value v)
900 return (size_t)Connection_val(v); /* address */
903 static struct custom_operations curl_easy_ops = {
904 "ygrek.curl_easy",
905 op_curl_easy_finalize,
906 op_curl_easy_compare,
907 op_curl_easy_hash,
908 custom_serialize_default,
909 custom_deserialize_default,
910 #if defined(custom_compare_ext_default)
911 custom_compare_ext_default,
912 #endif
915 value caml_curl_alloc(Connection* conn)
917 value v = caml_alloc_custom(&curl_easy_ops, sizeof(Connection*), 0, 1);
918 Connection_val(v) = conn;
919 conn->refcount++;
920 return v;
923 static size_t cb_WRITEFUNCTION(char *ptr, size_t size, size_t nmemb, void *data)
925 caml_leave_blocking_section();
927 CAMLparam0();
928 CAMLlocal2(result, str);
929 Connection *conn = (Connection *)data;
931 checkConnection(conn);
933 str = ml_copy_string(ptr,size*nmemb);
935 result = caml_callback_exn(Field(conn->ocamlValues, Ocaml_WRITEFUNCTION), str);
937 size_t r = Is_exception_result(result) ? 0 : Int_val(result);
938 CAMLdrop;
940 caml_enter_blocking_section();
941 return r;
944 static size_t cb_READFUNCTION(void *ptr, size_t size, size_t nmemb, void *data)
946 caml_leave_blocking_section();
948 CAMLparam0();
949 CAMLlocal1(result);
950 Connection *conn = (Connection *)data;
951 size_t length;
953 checkConnection(conn);
955 result = caml_callback_exn(Field(conn->ocamlValues, Ocaml_READFUNCTION),
956 Val_int(size*nmemb));
958 if (Is_exception_result(result))
960 CAMLreturnT(size_t,CURL_READFUNC_ABORT);
963 length = caml_string_length(result);
965 size_t r;
967 if (length <= size*nmemb)
969 memcpy(ptr, String_val(result), length);
970 r = length;
972 else
974 r = CURL_READFUNC_ABORT;
976 CAMLdrop;
978 caml_enter_blocking_section();
979 return r;
982 static size_t cb_HEADERFUNCTION(char *ptr, size_t size, size_t nmemb, void *data)
984 caml_leave_blocking_section();
986 CAMLparam0();
987 CAMLlocal2(result,str);
988 Connection *conn = (Connection *)data;
990 checkConnection(conn);
992 str = ml_copy_string(ptr,size*nmemb);
994 result = caml_callback_exn(Field(conn->ocamlValues, Ocaml_HEADERFUNCTION), str);
996 size_t r = Is_exception_result(result) ? 0 : Int_val(result);
997 CAMLdrop;
999 caml_enter_blocking_section();
1000 return r;
1003 static int cb_PROGRESSFUNCTION(void *data,
1004 double dlTotal,
1005 double dlNow,
1006 double ulTotal,
1007 double ulNow)
1009 caml_leave_blocking_section();
1011 CAMLparam0();
1012 CAMLlocal1(result);
1013 CAMLlocalN(callbackData, 4);
1014 Connection *conn = (Connection *)data;
1016 checkConnection(conn);
1018 callbackData[0] = caml_copy_double(dlTotal);
1019 callbackData[1] = caml_copy_double(dlNow);
1020 callbackData[2] = caml_copy_double(ulTotal);
1021 callbackData[3] = caml_copy_double(ulNow);
1023 result = caml_callbackN_exn(Field(conn->ocamlValues, Ocaml_PROGRESSFUNCTION),
1024 4, callbackData);
1026 int r = Is_exception_result(result) ? 1 : Bool_val(result);
1027 CAMLdrop;
1029 caml_enter_blocking_section();
1030 return r;
1033 static int cb_DEBUGFUNCTION(CURL *debugConnection,
1034 curl_infotype infoType,
1035 char *buffer,
1036 size_t bufferLength,
1037 void *data)
1039 caml_leave_blocking_section();
1041 CAMLparam0();
1042 CAMLlocal3(camlDebugConnection, camlInfoType, camlMessage);
1043 Connection *conn = (Connection *)data;
1044 (void)debugConnection; /* not used */
1046 checkConnection(conn);
1048 camlDebugConnection = caml_curl_alloc(conn);
1049 camlInfoType = Val_long(infoType);
1050 camlMessage = ml_copy_string(buffer,bufferLength);
1052 caml_callback3_exn(Field(conn->ocamlValues, Ocaml_DEBUGFUNCTION),
1053 camlDebugConnection,
1054 camlInfoType,
1055 camlMessage);
1057 CAMLdrop;
1059 caml_enter_blocking_section();
1060 return 0;
1063 static curlioerr cb_IOCTLFUNCTION(CURL *ioctl,
1064 int cmd,
1065 void *data)
1067 caml_leave_blocking_section();
1069 CAMLparam0();
1070 CAMLlocal3(camlResult, camlConnection, camlCmd);
1071 Connection *conn = (Connection *)data;
1072 curlioerr result = CURLIOE_OK;
1073 (void)ioctl; /* not used */
1075 checkConnection(conn);
1077 if (cmd == CURLIOCMD_NOP)
1078 camlCmd = Val_long(0);
1079 else if (cmd == CURLIOCMD_RESTARTREAD)
1080 camlCmd = Val_long(1);
1081 else
1082 caml_failwith("Invalid IOCTL Cmd!");
1084 camlConnection = caml_curl_alloc(conn);
1086 camlResult = caml_callback2_exn(Field(conn->ocamlValues, Ocaml_IOCTLFUNCTION),
1087 camlConnection,
1088 camlCmd);
1090 if (Is_exception_result(camlResult))
1092 result = CURLIOE_FAILRESTART;
1094 else
1095 switch (Long_val(camlResult))
1097 case 0: /* CURLIOE_OK */
1098 result = CURLIOE_OK;
1099 break;
1101 case 1: /* CURLIOE_UNKNOWNCMD */
1102 result = CURLIOE_UNKNOWNCMD;
1103 break;
1105 case 2: /* CURLIOE_FAILRESTART */
1106 result = CURLIOE_FAILRESTART;
1107 break;
1109 default: /* Incorrect return value, but let's handle it */
1110 result = CURLIOE_FAILRESTART;
1111 break;
1113 CAMLdrop;
1115 caml_enter_blocking_section();
1116 return result;
1119 #if HAVE_DECL_CURLOPT_SEEKFUNCTION
1120 static int cb_SEEKFUNCTION(void *data,
1121 curl_off_t offset,
1122 int origin)
1124 caml_leave_blocking_section();
1126 CAMLparam0();
1127 CAMLlocal3(camlResult, camlOffset, camlOrigin);
1128 Connection *conn = (Connection *)data;
1130 camlOffset = caml_copy_int64(offset);
1132 if (origin == SEEK_SET)
1133 camlOrigin = Val_long(0);
1134 else if (origin == SEEK_CUR)
1135 camlOrigin = Val_long(1);
1136 else if (origin == SEEK_END)
1137 camlOrigin = Val_long(2);
1138 else
1139 caml_failwith("Invalid seek code");
1141 camlResult = caml_callback2_exn(Field(conn->ocamlValues,
1142 Ocaml_SEEKFUNCTION),
1143 camlOffset,
1144 camlOrigin);
1146 int result;
1147 if (Is_exception_result(camlResult))
1148 result = CURL_SEEKFUNC_FAIL;
1149 else
1150 switch (Int_val(camlResult))
1152 case 0: result = CURL_SEEKFUNC_OK; break;
1153 case 1: result = CURL_SEEKFUNC_FAIL; break;
1154 case 2: result = CURL_SEEKFUNC_CANTSEEK; break;
1155 default: caml_failwith("Invalid seek result");
1157 CAMLdrop;
1159 caml_enter_blocking_section();
1160 return result;
1162 #endif
1164 #if HAVE_DECL_CURLOPT_OPENSOCKETFUNCTION
1165 static int cb_OPENSOCKETFUNCTION(void *data,
1166 curlsocktype purpose,
1167 struct curl_sockaddr *addr)
1169 caml_leave_blocking_section();
1171 CAMLparam0();
1172 CAMLlocal1(result);
1173 Connection *conn = (Connection *)data;
1174 int sock = -1;
1175 (void)purpose; /* not used */
1177 sock = socket(addr->family, addr->socktype, addr->protocol);
1179 if (-1 != sock)
1181 /* FIXME windows */
1182 result = caml_callback_exn(Field(conn->ocamlValues, Ocaml_OPENSOCKETFUNCTION), Val_int(sock));
1183 if (Is_exception_result(result))
1185 close(sock);
1186 sock = -1;
1189 CAMLdrop;
1191 caml_enter_blocking_section();
1192 return ((sock == -1) ? CURL_SOCKET_BAD : sock);
1194 #endif
1197 ** curl_global_init helper function
1200 CAMLprim value helper_curl_global_init(value initOption)
1202 CAMLparam1(initOption);
1204 switch (Long_val(initOption))
1206 case 0: /* CURLINIT_GLOBALALL */
1207 CAMLreturn(Val_long(curl_global_init(CURL_GLOBAL_ALL)));
1208 break;
1210 case 1: /* CURLINIT_GLOBALSSL */
1211 CAMLreturn(Val_long(curl_global_init(CURL_GLOBAL_SSL)));
1212 break;
1214 case 2: /* CURLINIT_GLOBALWIN32 */
1215 CAMLreturn(Val_long(curl_global_init(CURL_GLOBAL_WIN32)));
1216 break;
1218 case 3: /* CURLINIT_GLOBALNOTHING */
1219 CAMLreturn(Val_long(curl_global_init(CURL_GLOBAL_NOTHING)));
1220 break;
1222 default:
1223 caml_failwith("Invalid Initialization Option");
1224 break;
1227 /* Keep compiler happy, we should never get here due to caml_failwith() */
1228 CAMLreturn(Val_unit);
1232 ** curl_global_cleanup helper function
1235 CAMLprim value helper_curl_global_cleanup(void)
1237 CAMLparam0();
1239 curl_global_cleanup();
1241 CAMLreturn(Val_unit);
1245 ** curl_easy_init helper function
1247 CAMLprim value helper_curl_easy_init(void)
1249 CAMLparam0();
1250 CAMLlocal1(result);
1252 result = caml_curl_alloc(newConnection());
1254 CAMLreturn(result);
1257 CAMLprim value helper_curl_easy_reset(value conn)
1259 CAMLparam1(conn);
1260 Connection *connection = Connection_val(conn);
1262 checkConnection(connection);
1263 curl_easy_reset(connection->handle);
1264 curl_easy_setopt(connection->handle, CURLOPT_PRIVATE, connection);
1265 resetOcamlValues(connection);
1267 CAMLreturn(Val_unit);
1271 ** curl_easy_setopt helper utility functions
1274 #define SETOPT_FUNCTION(name) \
1275 static void handle_##name##FUNCTION(Connection *conn, value option) \
1277 CAMLparam1(option); \
1278 CURLcode result = CURLE_OK; \
1279 Store_field(conn->ocamlValues, Ocaml_##name##FUNCTION, option); \
1280 result = curl_easy_setopt(conn->handle, CURLOPT_##name##FUNCTION, cb_##name##FUNCTION); \
1281 if (result != CURLE_OK) raiseError(conn, result); \
1282 result = curl_easy_setopt(conn->handle, CURLOPT_##name##DATA, conn); \
1283 if (result != CURLE_OK) raiseError(conn, result); \
1284 CAMLreturn0; \
1287 SETOPT_FUNCTION( WRITE)
1288 SETOPT_FUNCTION( READ)
1289 SETOPT_FUNCTION( HEADER)
1290 SETOPT_FUNCTION( PROGRESS)
1291 SETOPT_FUNCTION( DEBUG)
1293 #if HAVE_DECL_CURLOPT_SEEKFUNCTION
1294 SETOPT_FUNCTION( SEEK)
1295 #endif
1297 #if HAVE_DECL_CURLOPT_IOCTLFUNCTION
1298 SETOPT_FUNCTION( IOCTL)
1299 #endif
1301 #if HAVE_DECL_CURLOPT_OPENSOCKETFUNCTION
1302 SETOPT_FUNCTION( OPENSOCKET)
1303 #endif
1305 static void handle_slist(Connection *conn, struct curl_slist** slist, OcamlValue caml_option, CURLoption curl_option, value option)
1307 CAMLparam1(option);
1308 CURLcode result = CURLE_OK;
1310 Store_field(conn->ocamlValues, caml_option, option);
1312 free_curl_slist(*slist);
1313 *slist = NULL;
1315 while (Val_emptylist != option)
1317 *slist = curl_slist_append(*slist, String_val(Field(option, 0)));
1319 option = Field(option, 1);
1322 result = curl_easy_setopt(conn->handle, curl_option, *slist);
1324 if (result != CURLE_OK)
1325 raiseError(conn, result);
1327 CAMLreturn0;
1330 static long convert_bit_list(long *map, size_t map_size, value option)
1332 CAMLparam1(option);
1333 long bits = 0;
1334 int index;
1336 while (Val_emptylist != option)
1338 index = Int_val(Field(option, 0));
1339 if ((index < 0) || ((size_t)index >= map_size))
1340 caml_invalid_argument("convert_bit_list");
1342 bits |= map[index];
1344 option = Field(option, 1);
1347 CAMLreturnT(long, bits);
1350 #define SETOPT_STRING(name) \
1351 static void handle_##name(Connection *conn, value option) \
1353 CAMLparam1(option); \
1354 CURLcode result = CURLE_OK; \
1356 Store_field(conn->ocamlValues, Ocaml_##name, option); \
1358 if (conn->curl_##name != NULL) \
1359 free(conn->curl_##name); \
1361 conn->curl_##name = strdup(String_val(option)); \
1363 result = curl_easy_setopt(conn->handle, CURLOPT_##name, conn->curl_##name); \
1365 if (result != CURLE_OK) \
1366 raiseError(conn, result); \
1368 CAMLreturn0; \
1371 #define SETOPT_VAL_(func_name, curl_option, conv_val) \
1372 static void func_name(Connection *conn, value option) \
1374 CAMLparam1(option); \
1375 CURLcode result = CURLE_OK; \
1377 result = curl_easy_setopt(conn->handle, curl_option, conv_val(option)); \
1379 if (result != CURLE_OK) \
1380 raiseError(conn, result); \
1382 CAMLreturn0; \
1385 #define SETOPT_VAL(name, conv) SETOPT_VAL_(handle_##name, CURLOPT_##name, conv)
1386 #define SETOPT_BOOL(name) SETOPT_VAL(name, Bool_val)
1387 #define SETOPT_LONG(name) SETOPT_VAL(name, Long_val)
1388 #define SETOPT_INT64(name) SETOPT_VAL(name, Int64_val)
1390 #define SETOPT_SLIST(name) \
1391 static void handle_##name(Connection* conn, value option) \
1393 handle_slist(conn,&(conn->curl_##name),Ocaml_##name,CURLOPT_##name,option); \
1396 SETOPT_STRING( URL)
1397 SETOPT_LONG( INFILESIZE)
1398 SETOPT_STRING( PROXY)
1399 SETOPT_LONG( PROXYPORT)
1400 SETOPT_BOOL( HTTPPROXYTUNNEL)
1401 SETOPT_BOOL( VERBOSE)
1402 SETOPT_BOOL( HEADER)
1403 SETOPT_BOOL( NOPROGRESS)
1405 #if HAVE_DECL_CURLOPT_NOSIGNAL
1406 SETOPT_BOOL( NOSIGNAL)
1407 #endif
1409 SETOPT_BOOL( NOBODY)
1410 SETOPT_BOOL( FAILONERROR)
1411 SETOPT_BOOL( UPLOAD)
1412 SETOPT_BOOL( POST)
1413 SETOPT_BOOL( FTPLISTONLY)
1414 SETOPT_BOOL( FTPAPPEND)
1417 static void handle_NETRC(Connection *conn, value option)
1419 CAMLparam1(option);
1420 CURLcode result = CURLE_OK;
1421 long netrc;
1423 switch (Long_val(option))
1425 case 0: /* CURL_NETRC_OPTIONAL */
1426 netrc = CURL_NETRC_OPTIONAL;
1427 break;
1429 case 1:/* CURL_NETRC_IGNORED */
1430 netrc = CURL_NETRC_IGNORED;
1431 break;
1433 case 2: /* CURL_NETRC_REQUIRED */
1434 netrc = CURL_NETRC_REQUIRED;
1435 break;
1437 default:
1438 caml_failwith("Invalid NETRC Option");
1439 break;
1442 result = curl_easy_setopt(conn->handle,
1443 CURLOPT_NETRC,
1444 netrc);
1446 if (result != CURLE_OK)
1447 raiseError(conn, result);
1449 CAMLreturn0;
1452 #if HAVE_DECL_CURLOPT_ENCODING
1453 static void handle_ENCODING(Connection *conn, value option)
1455 CAMLparam1(option);
1456 CURLcode result = CURLE_OK;
1458 switch (Long_val(option))
1460 case 0: /* CURL_ENCODING_NONE */
1461 result = curl_easy_setopt(conn->handle,
1462 CURLOPT_ENCODING,
1463 "identity");
1464 break;
1466 case 1: /* CURL_ENCODING_DEFLATE */
1467 result = curl_easy_setopt(conn->handle,
1468 CURLOPT_ENCODING,
1469 "deflate");
1470 break;
1472 case 2: /* CURL_ENCODING_GZIP */
1473 result = curl_easy_setopt(conn->handle,
1474 CURLOPT_ENCODING,
1475 "gzip");
1476 break;
1478 case 3: /* CURL_ENCODING_ANY */
1479 result = curl_easy_setopt(conn->handle,
1480 CURLOPT_ENCODING,
1481 "");
1482 break;
1484 default:
1485 caml_failwith("Invalid Encoding Option");
1486 break;
1489 if (result != CURLE_OK)
1490 raiseError(conn, result);
1492 CAMLreturn0;
1494 #endif
1497 SETOPT_BOOL( FOLLOWLOCATION)
1498 SETOPT_BOOL( TRANSFERTEXT)
1499 SETOPT_BOOL( PUT)
1500 SETOPT_STRING( USERPWD)
1501 SETOPT_STRING( PROXYUSERPWD)
1502 SETOPT_STRING( RANGE)
1504 static void handle_ERRORBUFFER(Connection *conn, value option)
1506 CAMLparam1(option);
1507 CURLcode result = CURLE_OK;
1509 Store_field(conn->ocamlValues, Ocaml_ERRORBUFFER, option);
1511 if (conn->curl_ERRORBUFFER != NULL)
1512 free(conn->curl_ERRORBUFFER);
1514 conn->curl_ERRORBUFFER = (char*)malloc(sizeof(char) * CURL_ERROR_SIZE);
1516 result = curl_easy_setopt(conn->handle,
1517 CURLOPT_ERRORBUFFER,
1518 conn->curl_ERRORBUFFER);
1520 if (result != CURLE_OK)
1521 raiseError(conn, result);
1523 CAMLreturn0;
1526 SETOPT_LONG( TIMEOUT)
1528 static void handle_POSTFIELDS(Connection *conn, value option)
1530 CAMLparam1(option);
1531 CURLcode result = CURLE_OK;
1533 Store_field(conn->ocamlValues, Ocaml_POSTFIELDS, option);
1535 if (conn->curl_POSTFIELDS != NULL)
1536 free(conn->curl_POSTFIELDS);
1538 conn->curl_POSTFIELDS = strdup_ml(option);
1540 result = curl_easy_setopt(conn->handle,
1541 CURLOPT_POSTFIELDS,
1542 conn->curl_POSTFIELDS);
1544 if (result != CURLE_OK)
1545 raiseError(conn, result);
1547 CAMLreturn0;
1550 SETOPT_LONG( POSTFIELDSIZE)
1551 SETOPT_STRING( REFERER)
1552 SETOPT_STRING( USERAGENT)
1553 SETOPT_STRING( FTPPORT)
1554 SETOPT_LONG( LOW_SPEED_LIMIT)
1555 SETOPT_LONG( LOW_SPEED_TIME)
1556 SETOPT_LONG( RESUME_FROM)
1557 SETOPT_STRING( COOKIE)
1559 SETOPT_SLIST( HTTPHEADER)
1561 static void handle_HTTPPOST(Connection *conn, value option)
1563 CAMLparam1(option);
1564 CAMLlocal3(listIter, formItem, contentType);
1565 CURLcode result = CURLE_OK;
1567 listIter = option;
1569 Store_field(conn->ocamlValues, Ocaml_HTTPPOST, option);
1571 free_curl_slist(conn->httpPostBuffers);
1572 if (conn->httpPostFirst != NULL)
1573 curl_formfree(conn->httpPostFirst);
1575 conn->httpPostBuffers = NULL;
1576 conn->httpPostFirst = NULL;
1577 conn->httpPostLast = NULL;
1579 while (!Is_long(listIter))
1581 formItem = Field(listIter, 0);
1583 switch (Tag_val(formItem))
1585 case 0: /* CURLFORM_CONTENT */
1586 if (Wosize_val(formItem) < 3)
1588 caml_failwith("Incorrect CURLFORM_CONTENT parameters");
1591 if (Is_long(Field(formItem, 2)) &&
1592 Long_val(Field(formItem, 2)) == 0)
1594 curl_formadd(&conn->httpPostFirst,
1595 &conn->httpPostLast,
1596 CURLFORM_COPYNAME,
1597 String_val(Field(formItem, 0)),
1598 CURLFORM_NAMELENGTH,
1599 caml_string_length(Field(formItem, 0)),
1600 CURLFORM_COPYCONTENTS,
1601 String_val(Field(formItem, 1)),
1602 CURLFORM_CONTENTSLENGTH,
1603 caml_string_length(Field(formItem, 1)),
1604 CURLFORM_END);
1606 else if (Is_block(Field(formItem, 2)))
1608 contentType = Field(formItem, 2);
1610 curl_formadd(&conn->httpPostFirst,
1611 &conn->httpPostLast,
1612 CURLFORM_COPYNAME,
1613 String_val(Field(formItem, 0)),
1614 CURLFORM_NAMELENGTH,
1615 caml_string_length(Field(formItem, 0)),
1616 CURLFORM_COPYCONTENTS,
1617 String_val(Field(formItem, 1)),
1618 CURLFORM_CONTENTSLENGTH,
1619 caml_string_length(Field(formItem, 1)),
1620 CURLFORM_CONTENTTYPE,
1621 String_val(Field(contentType, 0)),
1622 CURLFORM_END);
1624 else
1626 caml_failwith("Incorrect CURLFORM_CONTENT parameters");
1628 break;
1630 case 1: /* CURLFORM_FILECONTENT */
1631 if (Wosize_val(formItem) < 3)
1633 caml_failwith("Incorrect CURLFORM_FILECONTENT parameters");
1636 if (Is_long(Field(formItem, 2)) &&
1637 Long_val(Field(formItem, 2)) == 0)
1639 curl_formadd(&conn->httpPostFirst,
1640 &conn->httpPostLast,
1641 CURLFORM_COPYNAME,
1642 String_val(Field(formItem, 0)),
1643 CURLFORM_NAMELENGTH,
1644 caml_string_length(Field(formItem, 0)),
1645 CURLFORM_FILECONTENT,
1646 String_val(Field(formItem, 1)),
1647 CURLFORM_END);
1649 else if (Is_block(Field(formItem, 2)))
1651 contentType = Field(formItem, 2);
1653 curl_formadd(&conn->httpPostFirst,
1654 &conn->httpPostLast,
1655 CURLFORM_COPYNAME,
1656 String_val(Field(formItem, 0)),
1657 CURLFORM_NAMELENGTH,
1658 caml_string_length(Field(formItem, 0)),
1659 CURLFORM_FILECONTENT,
1660 String_val(Field(formItem, 1)),
1661 CURLFORM_CONTENTTYPE,
1662 String_val(Field(contentType, 0)),
1663 CURLFORM_END);
1665 else
1667 caml_failwith("Incorrect CURLFORM_FILECONTENT parameters");
1669 break;
1671 case 2: /* CURLFORM_FILE */
1672 if (Wosize_val(formItem) < 3)
1674 caml_failwith("Incorrect CURLFORM_FILE parameters");
1677 if (Is_long(Field(formItem, 2)) &&
1678 Long_val(Field(formItem, 2)) == 0)
1680 curl_formadd(&conn->httpPostFirst,
1681 &conn->httpPostLast,
1682 CURLFORM_COPYNAME,
1683 String_val(Field(formItem, 0)),
1684 CURLFORM_NAMELENGTH,
1685 caml_string_length(Field(formItem, 0)),
1686 CURLFORM_FILE,
1687 String_val(Field(formItem, 1)),
1688 CURLFORM_END);
1690 else if (Is_block(Field(formItem, 2)))
1692 contentType = Field(formItem, 2);
1694 curl_formadd(&conn->httpPostFirst,
1695 &conn->httpPostLast,
1696 CURLFORM_COPYNAME,
1697 String_val(Field(formItem, 0)),
1698 CURLFORM_NAMELENGTH,
1699 caml_string_length(Field(formItem, 0)),
1700 CURLFORM_FILE,
1701 String_val(Field(formItem, 1)),
1702 CURLFORM_CONTENTTYPE,
1703 String_val(Field(contentType, 0)),
1704 CURLFORM_END);
1706 else
1708 caml_failwith("Incorrect CURLFORM_FILE parameters");
1710 break;
1712 case 3: /* CURLFORM_BUFFER */
1713 if (Wosize_val(formItem) < 4)
1715 caml_failwith("Incorrect CURLFORM_BUFFER parameters");
1718 if (Is_long(Field(formItem, 3)) &&
1719 Long_val(Field(formItem, 3)) == 0)
1721 conn->httpPostBuffers = curl_slist_prepend_ml(conn->httpPostBuffers, Field(formItem, 2));
1723 curl_formadd(&conn->httpPostFirst,
1724 &conn->httpPostLast,
1725 CURLFORM_COPYNAME,
1726 String_val(Field(formItem, 0)),
1727 CURLFORM_NAMELENGTH,
1728 caml_string_length(Field(formItem, 0)),
1729 CURLFORM_BUFFER,
1730 String_val(Field(formItem, 1)),
1731 CURLFORM_BUFFERPTR,
1732 conn->httpPostBuffers->data,
1733 CURLFORM_BUFFERLENGTH,
1734 caml_string_length(Field(formItem, 2)),
1735 CURLFORM_END);
1737 else if (Is_block(Field(formItem, 3)))
1739 conn->httpPostBuffers = curl_slist_prepend_ml(conn->httpPostBuffers, Field(formItem, 2));
1741 contentType = Field(formItem, 3);
1743 curl_formadd(&conn->httpPostFirst,
1744 &conn->httpPostLast,
1745 CURLFORM_COPYNAME,
1746 String_val(Field(formItem, 0)),
1747 CURLFORM_NAMELENGTH,
1748 caml_string_length(Field(formItem, 0)),
1749 CURLFORM_BUFFER,
1750 String_val(Field(formItem, 1)),
1751 CURLFORM_BUFFERPTR,
1752 conn->httpPostBuffers->data,
1753 CURLFORM_BUFFERLENGTH,
1754 caml_string_length(Field(formItem, 2)),
1755 CURLFORM_CONTENTTYPE,
1756 String_val(Field(contentType, 0)),
1757 CURLFORM_END);
1759 else
1761 caml_failwith("Incorrect CURLFORM_BUFFER parameters");
1763 break;
1766 listIter = Field(listIter, 1);
1769 result = curl_easy_setopt(conn->handle,
1770 CURLOPT_HTTPPOST,
1771 conn->httpPostFirst);
1773 if (result != CURLE_OK)
1774 raiseError(conn, result);
1776 CAMLreturn0;
1779 SETOPT_STRING( SSLCERT)
1780 SETOPT_STRING( SSLCERTTYPE)
1781 SETOPT_STRING( SSLCERTPASSWD)
1782 SETOPT_STRING( SSLKEY)
1783 SETOPT_STRING( SSLKEYTYPE)
1784 SETOPT_STRING( SSLKEYPASSWD)
1785 SETOPT_STRING( SSLENGINE)
1786 SETOPT_BOOL( SSLENGINE_DEFAULT)
1787 SETOPT_BOOL( CRLF)
1789 SETOPT_SLIST( QUOTE)
1790 SETOPT_SLIST( POSTQUOTE)
1792 SETOPT_STRING( COOKIEFILE)
1793 #if HAVE_DECL_CURLOPT_CERTINFO
1794 SETOPT_BOOL( CERTINFO)
1795 #endif
1797 #if !defined(CURL_SSLVERSION_TLSv1_0)
1798 #define CURL_SSLVERSION_TLSv1_0 CURL_SSLVERSION_TLSv1
1799 #endif
1801 #if !defined(CURL_SSLVERSION_TLSv1_1)
1802 #define CURL_SSLVERSION_TLSv1_1 CURL_SSLVERSION_TLSv1
1803 #endif
1805 #if !defined(CURL_SSLVERSION_TLSv1_2)
1806 #define CURL_SSLVERSION_TLSv1_2 CURL_SSLVERSION_TLSv1
1807 #endif
1809 #if !defined(CURL_SSLVERSION_TLSv1_3)
1810 #define CURL_SSLVERSION_TLSv1_3 CURL_SSLVERSION_TLSv1
1811 #endif
1813 static void handle_SSLVERSION(Connection *conn, value option)
1815 CAMLparam1(option);
1816 CURLcode result = CURLE_OK;
1817 int v = CURL_SSLVERSION_DEFAULT;
1819 switch (Long_val(option))
1821 case 0: v = CURL_SSLVERSION_DEFAULT; break;
1822 case 1: v = CURL_SSLVERSION_TLSv1; break;
1823 case 2: v = CURL_SSLVERSION_SSLv2; break;
1824 case 3: v = CURL_SSLVERSION_SSLv3; break;
1825 case 4: v = CURL_SSLVERSION_TLSv1_0; break;
1826 case 5: v = CURL_SSLVERSION_TLSv1_1; break;
1827 case 6: v = CURL_SSLVERSION_TLSv1_2; break;
1828 case 7: v = CURL_SSLVERSION_TLSv1_3; break;
1829 default:
1830 caml_failwith("Invalid SSLVERSION Option");
1831 break;
1834 result = curl_easy_setopt(conn->handle, CURLOPT_SSLVERSION, v);
1836 if (result != CURLE_OK)
1837 raiseError(conn, result);
1839 CAMLreturn0;
1842 static void handle_TIMECONDITION(Connection *conn, value option)
1844 CAMLparam1(option);
1845 CURLcode result = CURLE_OK;
1846 int timecond = CURL_TIMECOND_NONE;
1848 switch (Long_val(option))
1850 case 0: timecond = CURL_TIMECOND_NONE; break;
1851 case 1: timecond = CURL_TIMECOND_IFMODSINCE; break;
1852 case 2: timecond = CURL_TIMECOND_IFUNMODSINCE; break;
1853 case 3: timecond = CURL_TIMECOND_LASTMOD; break;
1854 default:
1855 caml_failwith("Invalid TIMECOND Option");
1856 break;
1859 result = curl_easy_setopt(conn->handle, CURLOPT_TIMECONDITION, timecond);
1861 if (result != CURLE_OK)
1862 raiseError(conn, result);
1864 CAMLreturn0;
1867 SETOPT_VAL( TIMEVALUE, Int32_val)
1868 SETOPT_STRING( CUSTOMREQUEST)
1869 SETOPT_STRING( INTERFACE)
1871 static void handle_KRB4LEVEL(Connection *conn, value option)
1873 CAMLparam1(option);
1874 CURLcode result = CURLE_OK;
1876 switch (Long_val(option))
1878 case 0: /* KRB4_NONE */
1879 result = curl_easy_setopt(conn->handle,
1880 CURLOPT_KRB4LEVEL,
1881 NULL);
1882 break;
1884 case 1: /* KRB4_CLEAR */
1885 result = curl_easy_setopt(conn->handle,
1886 CURLOPT_KRB4LEVEL,
1887 "clear");
1888 break;
1890 case 2: /* KRB4_SAFE */
1891 result = curl_easy_setopt(conn->handle,
1892 CURLOPT_KRB4LEVEL,
1893 "safe");
1894 break;
1896 case 3: /* KRB4_CONFIDENTIAL */
1897 result = curl_easy_setopt(conn->handle,
1898 CURLOPT_KRB4LEVEL,
1899 "confidential");
1900 break;
1902 case 4: /* KRB4_PRIVATE */
1903 result = curl_easy_setopt(conn->handle,
1904 CURLOPT_KRB4LEVEL,
1905 "private");
1906 break;
1908 default:
1909 caml_failwith("Invalid KRB4 Option");
1910 break;
1913 if (result != CURLE_OK)
1914 raiseError(conn, result);
1916 CAMLreturn0;
1919 SETOPT_BOOL( SSL_VERIFYPEER)
1920 SETOPT_STRING( CAINFO)
1921 SETOPT_STRING( CAPATH)
1922 SETOPT_BOOL( FILETIME)
1923 SETOPT_LONG( MAXREDIRS)
1924 SETOPT_LONG( MAXCONNECTS)
1926 static void handle_CLOSEPOLICY(Connection *conn, value option)
1928 CAMLparam1(option);
1929 CURLcode result = CURLE_OK;
1931 switch (Long_val(option))
1933 case 0: /* CLOSEPOLICY_OLDEST */
1934 result = curl_easy_setopt(conn->handle,
1935 CURLOPT_CLOSEPOLICY,
1936 CURLCLOSEPOLICY_OLDEST);
1937 break;
1939 case 1: /* CLOSEPOLICY_LEAST_RECENTLY_USED */
1940 result = curl_easy_setopt(conn->handle,
1941 CURLOPT_CLOSEPOLICY,
1942 CURLCLOSEPOLICY_LEAST_RECENTLY_USED);
1943 break;
1945 default:
1946 caml_failwith("Invalid CLOSEPOLICY Option");
1947 break;
1950 if (result != CURLE_OK)
1951 raiseError(conn, result);
1953 CAMLreturn0;
1956 SETOPT_BOOL( FRESH_CONNECT)
1957 SETOPT_BOOL( FORBID_REUSE)
1958 SETOPT_STRING( RANDOM_FILE)
1959 SETOPT_STRING( EGDSOCKET)
1960 SETOPT_LONG( CONNECTTIMEOUT)
1961 SETOPT_BOOL( HTTPGET)
1963 static void handle_SSL_VERIFYHOST(Connection *conn, value option)
1965 CAMLparam1(option);
1966 CURLcode result = CURLE_OK;
1968 switch (Long_val(option))
1970 case 0: /* SSLVERIFYHOST_NONE */
1971 case 1: /* SSLVERIFYHOST_EXISTENCE */
1972 case 2: /* SSLVERIFYHOST_HOSTNAME */
1973 result = curl_easy_setopt(conn->handle,
1974 CURLOPT_SSL_VERIFYHOST,
1975 /* map EXISTENCE to HOSTNAME */
1976 Long_val(option) == 0 ? 0 : 2);
1977 break;
1979 default:
1980 caml_failwith("Invalid SSLVERIFYHOST Option");
1981 break;
1984 if (result != CURLE_OK)
1985 raiseError(conn, result);
1987 CAMLreturn0;
1990 SETOPT_STRING( COOKIEJAR)
1991 SETOPT_STRING( SSL_CIPHER_LIST)
1993 static void handle_HTTP_VERSION(Connection *conn, value option)
1995 CAMLparam1(option);
1996 CURLcode result = CURLE_OK;
1998 long version = CURL_HTTP_VERSION_NONE;
2000 switch (Long_val(option))
2002 case 0: version = CURL_HTTP_VERSION_NONE; break;
2003 case 1: version = CURL_HTTP_VERSION_1_0; break;
2004 case 2: version = CURL_HTTP_VERSION_1_1; break;
2005 case 3:
2006 #if defined(CURL_HTTP_VERSION_2)
2007 version = CURL_HTTP_VERSION_2;
2008 #elif defined(CURL_HTTP_VERSION_2_0)
2009 version = CURL_HTTP_VERSION_2_0;
2010 #endif
2011 break;
2012 case 4:
2013 #if defined(CURL_HTTP_VERSION_2TLS)
2014 version = CURL_HTTP_VERSION_2TLS;
2015 #endif
2016 break;
2017 default:
2018 caml_invalid_argument("CURLOPT_HTTP_VERSION");
2019 break;
2022 result = curl_easy_setopt(conn->handle, CURLOPT_HTTP_VERSION, version);
2024 if (result != CURLE_OK)
2025 raiseError(conn, result);
2027 CAMLreturn0;
2030 SETOPT_BOOL( FTP_USE_EPSV)
2031 SETOPT_LONG( DNS_CACHE_TIMEOUT)
2032 SETOPT_BOOL( DNS_USE_GLOBAL_CACHE)
2034 static void handle_PRIVATE(Connection *conn, value option)
2036 CAMLparam1(option);
2037 Store_field(conn->ocamlValues, Ocaml_PRIVATE, option);
2038 CAMLreturn0;
2041 #if HAVE_DECL_CURLOPT_HTTP200ALIASES
2042 SETOPT_SLIST( HTTP200ALIASES)
2043 #endif
2045 #if HAVE_DECL_CURLOPT_UNRESTRICTED_AUTH
2046 SETOPT_BOOL( UNRESTRICTED_AUTH)
2047 #endif
2049 #if HAVE_DECL_CURLOPT_FTP_USE_EPRT
2050 SETOPT_BOOL( FTP_USE_EPRT)
2051 #endif
2053 #if HAVE_DECL_CURLOPT_HTTPAUTH
2054 static void handle_HTTPAUTH(Connection *conn, value option)
2056 CAMLparam1(option);
2057 CAMLlocal1(listIter);
2058 CURLcode result = CURLE_OK;
2059 long auth = CURLAUTH_NONE;
2061 listIter = option;
2063 while (!Is_long(listIter))
2065 switch (Long_val(Field(listIter, 0)))
2067 case 0: /* CURLAUTH_BASIC */
2068 auth |= CURLAUTH_BASIC;
2069 break;
2071 case 1: /* CURLAUTH_DIGEST */
2072 auth |= CURLAUTH_DIGEST;
2073 break;
2075 case 2: /* CURLAUTH_GSSNEGOTIATE */
2076 auth |= CURLAUTH_GSSNEGOTIATE;
2077 break;
2079 case 3: /* CURLAUTH_NTLM */
2080 auth |= CURLAUTH_NTLM;
2081 break;
2083 case 4: /* CURLAUTH_ANY */
2084 auth |= CURLAUTH_ANY;
2085 break;
2087 case 5: /* CURLAUTH_ANYSAFE */
2088 auth |= CURLAUTH_ANYSAFE;
2089 break;
2091 default:
2092 caml_failwith("Invalid HTTPAUTH Value");
2093 break;
2096 listIter = Field(listIter, 1);
2099 result = curl_easy_setopt(conn->handle,
2100 CURLOPT_HTTPAUTH,
2101 auth);
2103 if (result != CURLE_OK)
2104 raiseError(conn, result);
2106 CAMLreturn0;
2108 #endif
2110 #if HAVE_DECL_CURLOPT_FTP_CREATE_MISSING_DIRS
2111 SETOPT_BOOL( FTP_CREATE_MISSING_DIRS)
2112 #endif
2114 #if HAVE_DECL_CURLOPT_PROXYAUTH
2115 static void handle_PROXYAUTH(Connection *conn, value option)
2117 CAMLparam1(option);
2118 CAMLlocal1(listIter);
2119 CURLcode result = CURLE_OK;
2120 long auth = CURLAUTH_NONE;
2122 listIter = option;
2124 while (!Is_long(listIter))
2126 switch (Long_val(Field(listIter, 0)))
2128 case 0: /* CURLAUTH_BASIC */
2129 auth |= CURLAUTH_BASIC;
2130 break;
2132 case 1: /* CURLAUTH_DIGEST */
2133 auth |= CURLAUTH_DIGEST;
2134 break;
2136 case 2: /* CURLAUTH_GSSNEGOTIATE */
2137 auth |= CURLAUTH_GSSNEGOTIATE;
2138 break;
2140 case 3: /* CURLAUTH_NTLM */
2141 auth |= CURLAUTH_NTLM;
2142 break;
2144 case 4: /* CURLAUTH_ANY */
2145 auth |= CURLAUTH_ANY;
2146 break;
2148 case 5: /* CURLAUTH_ANYSAFE */
2149 auth |= CURLAUTH_ANYSAFE;
2150 break;
2152 default:
2153 caml_failwith("Invalid HTTPAUTH Value");
2154 break;
2157 listIter = Field(listIter, 1);
2160 result = curl_easy_setopt(conn->handle,
2161 CURLOPT_PROXYAUTH,
2162 auth);
2164 if (result != CURLE_OK)
2165 raiseError(conn, result);
2167 CAMLreturn0;
2169 #endif
2171 #if HAVE_DECL_CURLOPT_FTP_RESPONSE_TIMEOUT
2172 SETOPT_LONG( FTP_RESPONSE_TIMEOUT)
2173 #endif
2175 #if HAVE_DECL_CURLOPT_IPRESOLVE
2176 static void handle_IPRESOLVE(Connection *conn, value option)
2178 CAMLparam1(option);
2179 CURLcode result = CURLE_OK;
2181 switch (Long_val(option))
2183 case 0: /* CURL_IPRESOLVE_WHATEVER */
2184 result = curl_easy_setopt(conn->handle,
2185 CURLOPT_IPRESOLVE,
2186 CURL_IPRESOLVE_WHATEVER);
2187 break;
2189 case 1: /* CURL_IPRESOLVE_V4 */
2190 result = curl_easy_setopt(conn->handle,
2191 CURLOPT_IPRESOLVE,
2192 CURL_IPRESOLVE_V4);
2193 break;
2195 case 2: /* CURL_IPRESOLVE_V6 */
2196 result = curl_easy_setopt(conn->handle,
2197 CURLOPT_IPRESOLVE,
2198 CURL_IPRESOLVE_V6);
2199 break;
2201 default:
2202 caml_failwith("Invalid IPRESOLVE Value");
2203 break;
2206 if (result != CURLE_OK)
2207 raiseError(conn, result);
2209 CAMLreturn0;
2211 #endif
2213 #if HAVE_DECL_CURLOPT_MAXFILESIZE
2214 SETOPT_VAL( MAXFILESIZE, Int32_val)
2215 #endif
2217 #if HAVE_DECL_CURLOPT_INFILESIZE_LARGE
2218 SETOPT_INT64( INFILESIZE_LARGE)
2219 #endif
2221 #if HAVE_DECL_CURLOPT_RESUME_FROM_LARGE
2222 SETOPT_INT64( RESUME_FROM_LARGE)
2223 #endif
2225 #if HAVE_DECL_CURLOPT_MAXFILESIZE_LARGE
2226 SETOPT_INT64( MAXFILESIZE_LARGE)
2227 #endif
2229 #if HAVE_DECL_CURLOPT_NETRC_FILE
2230 SETOPT_STRING( NETRC_FILE)
2231 #endif
2233 #if HAVE_DECL_CURLOPT_FTP_SSL
2234 static void handle_FTP_SSL(Connection *conn, value option)
2236 CAMLparam1(option);
2237 CURLcode result = CURLE_OK;
2239 switch (Long_val(option))
2241 case 0: /* CURLFTPSSL_NONE */
2242 result = curl_easy_setopt(conn->handle,
2243 CURLOPT_FTP_SSL,
2244 CURLFTPSSL_NONE);
2245 break;
2247 case 1: /* CURLFTPSSL_TRY */
2248 result = curl_easy_setopt(conn->handle,
2249 CURLOPT_FTP_SSL,
2250 CURLFTPSSL_TRY);
2251 break;
2253 case 2: /* CURLFTPSSL_CONTROL */
2254 result = curl_easy_setopt(conn->handle,
2255 CURLOPT_FTP_SSL,
2256 CURLFTPSSL_CONTROL);
2257 break;
2259 case 3: /* CURLFTPSSL_ALL */
2260 result = curl_easy_setopt(conn->handle,
2261 CURLOPT_FTP_SSL,
2262 CURLFTPSSL_ALL);
2263 break;
2265 default:
2266 caml_failwith("Invalid FTP_SSL Value");
2267 break;
2270 if (result != CURLE_OK)
2271 raiseError(conn, result);
2273 CAMLreturn0;
2275 #endif
2277 #if HAVE_DECL_CURLOPT_POSTFIELDSIZE_LARGE
2278 SETOPT_INT64( POSTFIELDSIZE_LARGE)
2279 #endif
2281 #if HAVE_DECL_CURLOPT_TCP_NODELAY
2282 /* not using SETOPT_BOOL here because of TCP_NODELAY defined in winsock.h */
2283 SETOPT_VAL_( handle_TCP_NODELAY, CURLOPT_TCP_NODELAY, Bool_val)
2284 #endif
2286 #if HAVE_DECL_CURLOPT_FTPSSLAUTH
2287 static void handle_FTPSSLAUTH(Connection *conn, value option)
2289 CAMLparam1(option);
2290 CURLcode result = CURLE_OK;
2292 switch (Long_val(option))
2294 case 0: /* CURLFTPAUTH_DEFAULT */
2295 result = curl_easy_setopt(conn->handle,
2296 CURLOPT_FTPSSLAUTH,
2297 CURLFTPAUTH_DEFAULT);
2298 break;
2300 case 1: /* CURLFTPAUTH_SSL */
2301 result = curl_easy_setopt(conn->handle,
2302 CURLOPT_FTPSSLAUTH,
2303 CURLFTPAUTH_SSL);
2304 break;
2306 case 2: /* CURLFTPAUTH_TLS */
2307 result = curl_easy_setopt(conn->handle,
2308 CURLOPT_FTPSSLAUTH,
2309 CURLFTPAUTH_TLS);
2310 break;
2312 default:
2313 caml_failwith("Invalid FTPSSLAUTH value");
2314 break;
2317 if (result != CURLE_OK)
2318 raiseError(conn, result);
2320 CAMLreturn0;
2322 #endif
2324 #if HAVE_DECL_CURLOPT_FTP_ACCOUNT
2325 SETOPT_STRING( FTP_ACCOUNT)
2326 #endif
2328 #if HAVE_DECL_CURLOPT_COOKIELIST
2329 SETOPT_STRING( COOKIELIST)
2330 #endif
2332 #if HAVE_DECL_CURLOPT_IGNORE_CONTENT_LENGTH
2333 SETOPT_BOOL( IGNORE_CONTENT_LENGTH)
2334 #endif
2336 #if HAVE_DECL_CURLOPT_FTP_SKIP_PASV_IP
2337 SETOPT_BOOL( FTP_SKIP_PASV_IP)
2338 #endif
2340 #if HAVE_DECL_CURLOPT_FTP_FILEMETHOD
2341 static void handle_FTP_FILEMETHOD(Connection *conn, value option)
2343 CAMLparam1(option);
2344 CURLcode result = CURLE_OK;
2346 switch (Long_val(option))
2348 case 0: /* CURLFTPMETHOD_DEFAULT */
2349 result = curl_easy_setopt(conn->handle,
2350 CURLOPT_FTP_FILEMETHOD,
2351 CURLFTPMETHOD_DEFAULT);
2352 break;
2354 case 1: /* CURLFTMETHOD_MULTICWD */
2355 result = curl_easy_setopt(conn->handle,
2356 CURLOPT_FTP_FILEMETHOD,
2357 CURLFTPMETHOD_MULTICWD);
2358 break;
2360 case 2: /* CURLFTPMETHOD_NOCWD */
2361 result = curl_easy_setopt(conn->handle,
2362 CURLOPT_FTP_FILEMETHOD,
2363 CURLFTPMETHOD_NOCWD);
2364 break;
2366 case 3: /* CURLFTPMETHOD_SINGLECWD */
2367 result = curl_easy_setopt(conn->handle,
2368 CURLOPT_FTP_FILEMETHOD,
2369 CURLFTPMETHOD_SINGLECWD);
2371 default:
2372 caml_failwith("Invalid FTP_FILEMETHOD value");
2373 break;
2376 if (result != CURLE_OK)
2377 raiseError(conn, result);
2379 CAMLreturn0;
2381 #endif
2383 #if HAVE_DECL_CURLOPT_LOCALPORT
2384 SETOPT_LONG( LOCALPORT)
2385 #endif
2387 #if HAVE_DECL_CURLOPT_LOCALPORTRANGE
2388 SETOPT_LONG( LOCALPORTRANGE)
2389 #endif
2391 #if HAVE_DECL_CURLOPT_CONNECT_ONLY
2392 SETOPT_BOOL( CONNECT_ONLY)
2393 #endif
2395 #if HAVE_DECL_CURLOPT_MAX_SEND_SPEED_LARGE
2396 SETOPT_INT64( MAX_SEND_SPEED_LARGE)
2397 #endif
2399 #if HAVE_DECL_CURLOPT_MAX_RECV_SPEED_LARGE
2400 SETOPT_INT64( MAX_RECV_SPEED_LARGE)
2401 #endif
2403 #if HAVE_DECL_CURLOPT_FTP_ALTERNATIVE_TO_USER
2404 SETOPT_STRING( FTP_ALTERNATIVE_TO_USER)
2405 #endif
2407 #if HAVE_DECL_CURLOPT_SSL_SESSIONID_CACHE
2408 SETOPT_BOOL( SSL_SESSIONID_CACHE)
2409 #endif
2411 #if HAVE_DECL_CURLOPT_SSH_AUTH_TYPES
2412 static void handle_SSH_AUTH_TYPES(Connection *conn, value option)
2414 CAMLparam1(option);
2415 CAMLlocal1(listIter);
2416 CURLcode result = CURLE_OK;
2417 long authTypes = CURLSSH_AUTH_NONE;
2419 listIter = option;
2421 while (!Is_long(listIter))
2423 switch (Long_val(Field(listIter, 0)))
2425 case 0: /* CURLSSH_AUTH_ANY */
2426 authTypes |= CURLSSH_AUTH_ANY;
2427 break;
2429 case 1: /* CURLSSH_AUTH_PUBLICKEY */
2430 authTypes |= CURLSSH_AUTH_PUBLICKEY;
2431 break;
2433 case 2: /* CURLSSH_AUTH_PASSWORD */
2434 authTypes |= CURLSSH_AUTH_PASSWORD;
2435 break;
2437 case 3: /* CURLSSH_AUTH_HOST */
2438 authTypes |= CURLSSH_AUTH_HOST;
2439 break;
2441 case 4: /* CURLSSH_AUTH_KEYBOARD */
2442 authTypes |= CURLSSH_AUTH_KEYBOARD;
2443 break;
2445 default:
2446 caml_failwith("Invalid CURLSSH_AUTH_TYPES Value");
2447 break;
2450 listIter = Field(listIter, 1);
2453 result = curl_easy_setopt(conn->handle,
2454 CURLOPT_SSH_AUTH_TYPES,
2455 authTypes);
2457 if (result != CURLE_OK)
2458 raiseError(conn, result);
2460 CAMLreturn0;
2462 #endif
2464 #if HAVE_DECL_CURLOPT_SSH_PUBLIC_KEYFILE
2465 SETOPT_STRING( SSH_PUBLIC_KEYFILE)
2466 #endif
2468 #if HAVE_DECL_CURLOPT_SSH_PRIVATE_KEYFILE
2469 SETOPT_STRING( SSH_PRIVATE_KEYFILE)
2470 #endif
2472 #if HAVE_DECL_CURLOPT_FTP_SSL_CCC
2473 static void handle_FTP_SSL_CCC(Connection *conn, value option)
2475 CAMLparam1(option);
2476 CURLcode result = CURLE_OK;
2478 switch (Long_val(option))
2480 case 0: /* CURLFTPSSL_CCC_NONE */
2481 result = curl_easy_setopt(conn->handle,
2482 CURLOPT_FTP_SSL_CCC,
2483 CURLFTPSSL_CCC_NONE);
2484 break;
2486 case 1: /* CURLFTPSSL_CCC_PASSIVE */
2487 result = curl_easy_setopt(conn->handle,
2488 CURLOPT_FTP_SSL_CCC,
2489 CURLFTPSSL_CCC_PASSIVE);
2490 break;
2492 case 2: /* CURLFTPSSL_CCC_ACTIVE */
2493 result = curl_easy_setopt(conn->handle,
2494 CURLOPT_FTP_SSL_CCC,
2495 CURLFTPSSL_CCC_ACTIVE);
2496 break;
2498 default:
2499 caml_failwith("Invalid FTPSSL_CCC value");
2500 break;
2503 if (result != CURLE_OK)
2504 raiseError(conn, result);
2506 CAMLreturn0;
2508 #endif
2510 #if HAVE_DECL_CURLOPT_TIMEOUT_MS
2511 SETOPT_LONG( TIMEOUT_MS)
2512 #endif
2514 #if HAVE_DECL_CURLOPT_CONNECTTIMEOUT_MS
2515 SETOPT_LONG( CONNECTTIMEOUT_MS)
2516 #endif
2518 #if HAVE_DECL_CURLOPT_HTTP_TRANSFER_DECODING
2519 SETOPT_BOOL( HTTP_TRANSFER_DECODING)
2520 #endif
2522 #if HAVE_DECL_CURLOPT_HTTP_CONTENT_DECODING
2523 SETOPT_BOOL( HTTP_CONTENT_DECODING)
2524 #endif
2526 #if HAVE_DECL_CURLOPT_NEW_FILE_PERMS
2527 SETOPT_LONG( NEW_FILE_PERMS)
2528 #endif
2530 #if HAVE_DECL_CURLOPT_NEW_DIRECTORY_PERMS
2531 SETOPT_LONG( NEW_DIRECTORY_PERMS)
2532 #endif
2534 #if HAVE_DECL_CURLOPT_POST301
2535 SETOPT_BOOL( POST301)
2536 #endif
2538 #if HAVE_DECL_CURLOPT_SSH_HOST_PUBLIC_KEY_MD5
2539 SETOPT_STRING( SSH_HOST_PUBLIC_KEY_MD5)
2540 #endif
2542 #if HAVE_DECL_CURLOPT_COPYPOSTFIELDS
2543 SETOPT_STRING( COPYPOSTFIELDS)
2544 #endif
2546 #if HAVE_DECL_CURLOPT_PROXY_TRANSFER_MODE
2547 SETOPT_BOOL( PROXY_TRANSFER_MODE)
2548 #endif
2550 #if HAVE_DECL_CURLOPT_AUTOREFERER
2551 SETOPT_BOOL( AUTOREFERER)
2552 #endif
2554 #if HAVE_DECL_CURLOPT_PROXYTYPE
2555 static void handle_PROXYTYPE(Connection *conn, value option)
2557 CAMLparam1(option);
2558 CURLcode result = CURLE_OK;
2559 long proxy_type;
2561 switch (Long_val(option))
2563 case 0: proxy_type = CURLPROXY_HTTP; break;
2564 case 1: proxy_type = CURLPROXY_HTTP_1_0; break;
2565 case 2: proxy_type = CURLPROXY_SOCKS4; break;
2566 case 3: proxy_type = CURLPROXY_SOCKS5; break;
2567 case 4: proxy_type = CURLPROXY_SOCKS4A; break;
2568 case 5: proxy_type = CURLPROXY_SOCKS5_HOSTNAME; break;
2569 default:
2570 caml_failwith("Invalid curl proxy type");
2573 result = curl_easy_setopt(conn->handle,
2574 CURLOPT_PROXYTYPE,
2575 proxy_type);
2577 if (result != CURLE_OK)
2578 raiseError(conn, result);
2580 CAMLreturn0;
2582 #endif
2584 #if HAVE_DECL_CURLOPT_PROTOCOLS || HAVE_DECL_CURLOPT_REDIR_PROTOCOLS
2586 long protoMap[] =
2588 CURLPROTO_ALL,
2589 CURLPROTO_HTTP, CURLPROTO_HTTPS, CURLPROTO_FTP, CURLPROTO_FTPS, CURLPROTO_SCP, CURLPROTO_SFTP,
2590 CURLPROTO_TELNET, CURLPROTO_LDAP, CURLPROTO_LDAPS, CURLPROTO_DICT, CURLPROTO_FILE, CURLPROTO_TFTP,
2591 /* factor out with autoconf? */
2592 #if defined(CURLPROTO_IMAP)
2593 CURLPROTO_IMAP,
2594 #else
2596 #endif
2597 #if defined(CURLPROTO_IMAPS)
2598 CURLPROTO_IMAPS,
2599 #else
2601 #endif
2602 #if defined(CURLPROTO_POP3)
2603 CURLPROTO_POP3,
2604 #else
2606 #endif
2607 #if defined(CURLPROTO_POP3S)
2608 CURLPROTO_POP3S,
2609 #else
2611 #endif
2612 #if defined(CURLPROTO_SMTP)
2613 CURLPROTO_SMTP,
2614 #else
2616 #endif
2617 #if defined(CURLPROTO_SMTPS)
2618 CURLPROTO_SMTPS,
2619 #else
2621 #endif
2622 #if defined(CURLPROTO_RTSP)
2623 CURLPROTO_RTSP,
2624 #else
2626 #endif
2627 #if defined(CURLPROTO_RTMP)
2628 CURLPROTO_RTMP,
2629 #else
2631 #endif
2632 #if defined(CURLPROTO_RTMPT)
2633 CURLPROTO_RTMPT,
2634 #else
2636 #endif
2637 #if defined(CURLPROTO_RTMPE)
2638 CURLPROTO_RTMPE,
2639 #else
2641 #endif
2642 #if defined(CURLPROTO_RTMPTE)
2643 CURLPROTO_RTMPTE,
2644 #else
2646 #endif
2647 #if defined(CURLPROTO_RTMPS)
2648 CURLPROTO_RTMPS,
2649 #else
2651 #endif
2652 #if defined(CURLPROTO_RTMPTS)
2653 CURLPROTO_RTMPTS,
2654 #else
2656 #endif
2657 #if defined(CURLPROTO_GOPHER)
2658 CURLPROTO_GOPHER,
2659 #else
2661 #endif
2664 static void handle_PROTOCOLSOPTION(CURLoption curlopt, Connection *conn, value option)
2666 CAMLparam1(option);
2667 CURLcode result = CURLE_OK;
2668 long bits = convert_bit_list(protoMap, sizeof(protoMap) / sizeof(protoMap[0]), option);
2670 result = curl_easy_setopt(conn->handle, curlopt, bits);
2672 if (result != CURLE_OK)
2673 raiseError(conn, result);
2675 CAMLreturn0;
2677 #endif
2679 #if HAVE_DECL_CURLOPT_PROTOCOLS
2680 static void handle_PROTOCOLS(Connection *conn, value option)
2682 handle_PROTOCOLSOPTION(CURLOPT_PROTOCOLS, conn, option);
2684 #endif
2686 #if HAVE_DECL_CURLOPT_REDIR_PROTOCOLS
2687 static void handle_REDIR_PROTOCOLS(Connection *conn, value option)
2689 handle_PROTOCOLSOPTION(CURLOPT_REDIR_PROTOCOLS, conn, option);
2691 #endif
2693 #if HAVE_DECL_CURLOPT_RESOLVE
2694 SETOPT_SLIST( RESOLVE)
2695 #endif
2697 #if HAVE_DECL_CURLOPT_DNS_SERVERS
2698 SETOPT_STRING( DNS_SERVERS)
2699 #endif
2701 #if HAVE_DECL_CURLOPT_MAIL_FROM
2702 SETOPT_STRING( MAIL_FROM)
2703 #endif
2705 #if HAVE_DECL_CURLOPT_MAIL_RCPT
2706 SETOPT_SLIST( MAIL_RCPT)
2707 #endif
2709 #if HAVE_DECL_CURLOPT_PIPEWAIT
2710 SETOPT_BOOL( PIPEWAIT)
2711 #endif
2714 ** curl_easy_setopt helper function
2717 #define MAP(name) { handle_ ## name, "CURLOPT_"#name, Ocaml_##name }
2718 #define MAP_NO(name) { NULL, "CURLOPT_"#name , Ocaml_##name }
2719 #define IMM(name) { handle_ ## name, "CURLOPT_"#name, (OcamlValue)(-1) }
2720 #define IMM_NO(name) { NULL, "CURLOPT_"#name , (OcamlValue)(-1) }
2722 CURLOptionMapping implementedOptionMap[] =
2724 MAP(WRITEFUNCTION),
2725 MAP(READFUNCTION),
2726 IMM(INFILESIZE),
2727 MAP(URL),
2728 MAP(PROXY),
2729 IMM(PROXYPORT),
2730 IMM(HTTPPROXYTUNNEL),
2731 IMM(VERBOSE),
2732 IMM(HEADER),
2733 IMM(NOPROGRESS),
2734 #if HAVE_DECL_CURLOPT_NOSIGNAL
2735 IMM(NOSIGNAL),
2736 #else
2737 IMM_NO(NOSIGNAL),
2738 #endif
2739 IMM(NOBODY),
2740 IMM(FAILONERROR),
2741 IMM(UPLOAD),
2742 IMM(POST),
2743 IMM(FTPLISTONLY),
2744 IMM(FTPAPPEND),
2745 IMM(NETRC),
2746 #if HAVE_DECL_CURLOPT_ENCODING
2747 IMM(ENCODING),
2748 #else
2749 IMM_NO(ENCODING),
2750 #endif
2751 IMM(FOLLOWLOCATION),
2752 IMM(TRANSFERTEXT),
2753 IMM(PUT),
2754 MAP(USERPWD),
2755 MAP(PROXYUSERPWD),
2756 MAP(RANGE),
2757 IMM(ERRORBUFFER), /* mutable buffer, as output value, do not duplicate */
2758 IMM(TIMEOUT),
2759 MAP(POSTFIELDS),
2760 IMM(POSTFIELDSIZE),
2761 MAP(REFERER),
2762 MAP(USERAGENT),
2763 MAP(FTPPORT),
2764 IMM(LOW_SPEED_LIMIT),
2765 IMM(LOW_SPEED_TIME),
2766 IMM(RESUME_FROM),
2767 MAP(COOKIE),
2768 MAP(HTTPHEADER),
2769 MAP(HTTPPOST),
2770 MAP(SSLCERT),
2771 MAP(SSLCERTTYPE),
2772 MAP(SSLCERTPASSWD),
2773 MAP(SSLKEY),
2774 MAP(SSLKEYTYPE),
2775 MAP(SSLKEYPASSWD),
2776 MAP(SSLENGINE),
2777 IMM(SSLENGINE_DEFAULT),
2778 IMM(CRLF),
2779 MAP(QUOTE),
2780 MAP(POSTQUOTE),
2781 MAP(HEADERFUNCTION),
2782 MAP(COOKIEFILE),
2783 IMM(SSLVERSION),
2784 IMM(TIMECONDITION),
2785 IMM(TIMEVALUE),
2786 MAP(CUSTOMREQUEST),
2787 MAP(INTERFACE),
2788 IMM(KRB4LEVEL),
2789 MAP(PROGRESSFUNCTION),
2790 IMM(SSL_VERIFYPEER),
2791 MAP(CAINFO),
2792 MAP(CAPATH),
2793 IMM(FILETIME),
2794 IMM(MAXREDIRS),
2795 IMM(MAXCONNECTS),
2796 IMM(CLOSEPOLICY),
2797 IMM(FRESH_CONNECT),
2798 IMM(FORBID_REUSE),
2799 MAP(RANDOM_FILE),
2800 MAP(EGDSOCKET),
2801 IMM(CONNECTTIMEOUT),
2802 IMM(HTTPGET),
2803 IMM(SSL_VERIFYHOST),
2804 MAP(COOKIEJAR),
2805 MAP(SSL_CIPHER_LIST),
2806 IMM(HTTP_VERSION),
2807 IMM(FTP_USE_EPSV),
2808 IMM(DNS_CACHE_TIMEOUT),
2809 IMM(DNS_USE_GLOBAL_CACHE),
2810 MAP(DEBUGFUNCTION),
2811 MAP(PRIVATE),
2812 #if HAVE_DECL_CURLOPT_HTTP200ALIASES
2813 MAP(HTTP200ALIASES),
2814 #else
2815 MAP_NO(HTTP200ALIASES),
2816 #endif
2817 #if HAVE_DECL_CURLOPT_UNRESTRICTED_AUTH
2818 IMM(UNRESTRICTED_AUTH),
2819 #else
2820 IMM_NO(UNRESTRICTED_AUTH),
2821 #endif
2822 #if HAVE_DECL_CURLOPT_FTP_USE_EPRT
2823 IMM(FTP_USE_EPRT),
2824 #else
2825 IMM_NO(FTP_USE_EPRT),
2826 #endif
2827 #if HAVE_DECL_CURLOPT_HTTPAUTH
2828 IMM(HTTPAUTH),
2829 #else
2830 IMM_NO(HTTPAUTH),
2831 #endif
2832 #if HAVE_DECL_CURLOPT_FTP_CREATE_MISSING_DIRS
2833 IMM(FTP_CREATE_MISSING_DIRS),
2834 #else
2835 IMM_NO(FTP_CREATE_MISSING_DIRS),
2836 #endif
2837 #if HAVE_DECL_CURLOPT_PROXYAUTH
2838 IMM(PROXYAUTH),
2839 #else
2840 IMM_NO(PROXYAUTH),
2841 #endif
2842 #if HAVE_DECL_CURLOPT_FTP_RESPONSE_TIMEOUT
2843 IMM(FTP_RESPONSE_TIMEOUT),
2844 #else
2845 IMM_NO(FTP_RESPONSE_TIMEOUT),
2846 #endif
2847 #if HAVE_DECL_CURLOPT_IPRESOLVE
2848 IMM(IPRESOLVE),
2849 #else
2850 IMM_NO(IPRESOLVE),
2851 #endif
2852 #if HAVE_DECL_CURLOPT_MAXFILESIZE
2853 IMM(MAXFILESIZE),
2854 #else
2855 IMM_NO(MAXFILESIZE),
2856 #endif
2857 #if HAVE_DECL_CURLOPT_INFILESIZE_LARGE
2858 IMM(INFILESIZE_LARGE),
2859 #else
2860 IMM_NO(INFILESIZE_LARGE),
2861 #endif
2862 #if HAVE_DECL_CURLOPT_RESUME_FROM_LARGE
2863 IMM(RESUME_FROM_LARGE),
2864 #else
2865 IMM_NO(RESUME_FROM_LARGE),
2866 #endif
2867 #if HAVE_DECL_CURLOPT_MAXFILESIZE_LARGE
2868 IMM(MAXFILESIZE_LARGE),
2869 #else
2870 IMM_NO(MAXFILESIZE_LARGE),
2871 #endif
2872 #if HAVE_DECL_CURLOPT_NETRC_FILE
2873 MAP(NETRC_FILE),
2874 #else
2875 MAP_NO(NETRC_FILE),
2876 #endif
2877 #if HAVE_DECL_CURLOPT_FTP_SSL
2878 IMM(FTP_SSL),
2879 #else
2880 IMM_NO(FTP_SSL),
2881 #endif
2882 #if HAVE_DECL_CURLOPT_POSTFIELDSIZE_LARGE
2883 IMM(POSTFIELDSIZE_LARGE),
2884 #else
2885 IMM_NO(POSTFIELDSIZE_LARGE),
2886 #endif
2887 #if HAVE_DECL_CURLOPT_TCP_NODELAY
2888 IMM(TCP_NODELAY),
2889 #else
2890 IMM_NO(TCP_NODELAY),
2891 #endif
2892 #if HAVE_DECL_CURLOPT_FTPSSLAUTH
2893 IMM(FTPSSLAUTH),
2894 #else
2895 IMM_NO(FTPSSLAUTH),
2896 #endif
2897 #if HAVE_DECL_CURLOPT_IOCTLFUNCTION
2898 MAP(IOCTLFUNCTION),
2899 #else
2900 MAP_NO(IOCTLFUNCTION),
2901 #endif
2902 #if HAVE_DECL_CURLOPT_FTP_ACCOUNT
2903 MAP(FTP_ACCOUNT),
2904 #else
2905 MAP_NO(FTP_ACCOUNT),
2906 #endif
2907 #if HAVE_DECL_CURLOPT_COOKIELIST
2908 MAP(COOKIELIST),
2909 #else
2910 MAP_NO(COOKIELIST),
2911 #endif
2912 #if HAVE_DECL_CURLOPT_IGNORE_CONTENT_LENGTH
2913 IMM(IGNORE_CONTENT_LENGTH),
2914 #else
2915 IMM_NO(IGNORE_CONTENT_LENGTH),
2916 #endif
2917 #if HAVE_DECL_CURLOPT_FTP_SKIP_PASV_IP
2918 IMM(FTP_SKIP_PASV_IP),
2919 #else
2920 IMM_NO(FTP_SKIP_PASV_IP),
2921 #endif
2922 #if HAVE_DECL_CURLOPT_FTP_FILEMETHOD
2923 IMM(FTP_FILEMETHOD),
2924 #else
2925 IMM_NO(FTP_FILEMETHOD),
2926 #endif
2927 #if HAVE_DECL_CURLOPT_LOCALPORT
2928 IMM(LOCALPORT),
2929 #else
2930 IMM_NO(LOCALPORT),
2931 #endif
2932 #if HAVE_DECL_CURLOPT_LOCALPORTRANGE
2933 IMM(LOCALPORTRANGE),
2934 #else
2935 IMM_NO(LOCALPORTRANGE),
2936 #endif
2937 #if HAVE_DECL_CURLOPT_CONNECT_ONLY
2938 IMM(CONNECT_ONLY),
2939 #else
2940 IMM_NO(CONNECT_ONLY),
2941 #endif
2942 #if HAVE_DECL_CURLOPT_MAX_SEND_SPEED_LARGE
2943 IMM(MAX_SEND_SPEED_LARGE),
2944 #else
2945 IMM_NO(MAX_SEND_SPEED_LARGE),
2946 #endif
2947 #if HAVE_DECL_CURLOPT_MAX_RECV_SPEED_LARGE
2948 IMM(MAX_RECV_SPEED_LARGE),
2949 #else
2950 IMM_NO(MAX_RECV_SPEED_LARGE),
2951 #endif
2952 #if HAVE_DECL_CURLOPT_FTP_ALTERNATIVE_TO_USER
2953 MAP(FTP_ALTERNATIVE_TO_USER),
2954 #else
2955 MAP_NO(FTP_ALTERNATIVE_TO_USER),
2956 #endif
2957 #if HAVE_DECL_CURLOPT_SSL_SESSIONID_CACHE
2958 IMM(SSL_SESSIONID_CACHE),
2959 #else
2960 IMM_NO(SSL_SESSIONID_CACHE),
2961 #endif
2962 #if HAVE_DECL_CURLOPT_SSH_AUTH_TYPES
2963 IMM(SSH_AUTH_TYPES),
2964 #else
2965 IMM_NO(SSH_AUTH_TYPES),
2966 #endif
2967 #if HAVE_DECL_CURLOPT_SSH_PUBLIC_KEYFILE
2968 MAP(SSH_PUBLIC_KEYFILE),
2969 #else
2970 MAP_NO(SSH_PUBLIC_KEYFILE),
2971 #endif
2972 #if HAVE_DECL_CURLOPT_SSH_PRIVATE_KEYFILE
2973 MAP(SSH_PRIVATE_KEYFILE),
2974 #else
2975 MAP_NO(SSH_PRIVATE_KEYFILE),
2976 #endif
2977 #if HAVE_DECL_CURLOPT_FTP_SSL_CCC
2978 IMM(FTP_SSL_CCC),
2979 #else
2980 IMM_NO(FTP_SSL_CCC),
2981 #endif
2982 #if HAVE_DECL_CURLOPT_TIMEOUT_MS
2983 IMM(TIMEOUT_MS),
2984 #else
2985 IMM_NO(TIMEOUT_MS),
2986 #endif
2987 #if HAVE_DECL_CURLOPT_CONNECTTIMEOUT_MS
2988 IMM(CONNECTTIMEOUT_MS),
2989 #else
2990 IMM_NO(CONNECTTIMEOUT_MS),
2991 #endif
2992 #if HAVE_DECL_CURLOPT_HTTP_TRANSFER_DECODING
2993 IMM(HTTP_TRANSFER_DECODING),
2994 #else
2995 IMM_NO(HTTP_TRANSFER_DECODING),
2996 #endif
2997 #if HAVE_DECL_CURLOPT_HTTP_CONTENT_DECODING
2998 IMM(HTTP_CONTENT_DECODING),
2999 #else
3000 IMM_NO(HTTP_CONTENT_DECODING),
3001 #endif
3002 #if HAVE_DECL_CURLOPT_NEW_FILE_PERMS
3003 IMM(NEW_FILE_PERMS),
3004 #else
3005 IMM_NO(NEW_FILE_PERMS),
3006 #endif
3007 #if HAVE_DECL_CURLOPT_NEW_DIRECTORY_PERMS
3008 IMM(NEW_DIRECTORY_PERMS),
3009 #else
3010 IMM_NO(NEW_DIRECTORY_PERMS),
3011 #endif
3012 #if HAVE_DECL_CURLOPT_POST301
3013 IMM(POST301),
3014 #else
3015 IMM_NO(POST301),
3016 #endif
3017 #if HAVE_DECL_CURLOPT_SSH_HOST_PUBLIC_KEY_MD5
3018 MAP(SSH_HOST_PUBLIC_KEY_MD5),
3019 #else
3020 MAP_NO(SSH_HOST_PUBLIC_KEY_MD5),
3021 #endif
3022 #if HAVE_DECL_CURLOPT_COPYPOSTFIELDS
3023 MAP(COPYPOSTFIELDS),
3024 #else
3025 MAP_NO(COPYPOSTFIELDS),
3026 #endif
3027 #if HAVE_DECL_CURLOPT_PROXY_TRANSFER_MODE
3028 IMM(PROXY_TRANSFER_MODE),
3029 #else
3030 IMM_NO(PROXY_TRANSFER_MODE),
3031 #endif
3032 #if HAVE_DECL_CURLOPT_SEEKFUNCTION
3033 MAP(SEEKFUNCTION),
3034 #else
3035 MAP_NO(SEEKFUNCTION),
3036 #endif
3037 #if HAVE_DECL_CURLOPT_AUTOREFERER
3038 IMM(AUTOREFERER),
3039 #else
3040 IMM_NO(AUTOREFERER),
3041 #endif
3042 #if HAVE_DECL_CURLOPT_OPENSOCKETFUNCTION
3043 MAP(OPENSOCKETFUNCTION),
3044 #else
3045 MAP_NO(OPENSOCKETFUNCTION),
3046 #endif
3047 #if HAVE_DECL_CURLOPT_PROXYTYPE
3048 IMM(PROXYTYPE),
3049 #else
3050 IMM_NO(PROXYTYPE),
3051 #endif
3052 #if HAVE_DECL_CURLOPT_PROTOCOLS
3053 IMM(PROTOCOLS),
3054 #else
3055 IMM_NO(PROTOCOLS),
3056 #endif
3057 #if HAVE_DECL_CURLOPT_REDIR_PROTOCOLS
3058 IMM(REDIR_PROTOCOLS),
3059 #else
3060 IMM_NO(REDIR_PROTOCOLS),
3061 #endif
3062 #if HAVE_DECL_CURLOPT_RESOLVE
3063 MAP(RESOLVE),
3064 #else
3065 MAP_NO(RESOLVE),
3066 #endif
3067 #if HAVE_DECL_CURLOPT_DNS_SERVERS
3068 MAP(DNS_SERVERS),
3069 #else
3070 MAP_NO(DNS_SERVERS),
3071 #endif
3072 #if HAVE_DECL_CURLOPT_MAIL_FROM
3073 MAP(MAIL_FROM),
3074 #else
3075 MAP_NO(MAIL_FROM),
3076 #endif
3077 #if HAVE_DECL_CURLOPT_MAIL_RCPT
3078 MAP(MAIL_RCPT),
3079 #else
3080 MAP_NO(MAIL_RCPT),
3081 #endif
3082 #if HAVE_DECL_CURLOPT_PIPEWAIT
3083 IMM(PIPEWAIT),
3084 #else
3085 IMM_NO(PIPEWAIT),
3086 #endif
3087 #if HAVE_DECL_CURLOPT_CERTINFO
3088 IMM(CERTINFO),
3089 #else
3090 IMM_NO(CERTINFO),
3091 #endif
3094 static Connection *duplicateConnection(Connection *original)
3096 Connection *connection = NULL;
3097 CURL* h = NULL;
3098 size_t i = 0;
3099 CURLOptionMapping* self = NULL;
3101 caml_enter_blocking_section();
3102 h = curl_easy_duphandle(original->handle);
3103 caml_leave_blocking_section();
3105 connection = allocConnection(h);
3107 for (i = 0; i < sizeof(implementedOptionMap)/sizeof(CURLOptionMapping); i++)
3109 self = &implementedOptionMap[i];
3110 if (-1 == self->ocamlValue) continue;
3111 if (self->optionHandler && (Field(original->ocamlValues, self->ocamlValue) != Val_unit))
3113 self->optionHandler(connection, Field(original->ocamlValues, self->ocamlValue));
3117 return connection;
3120 CAMLprim value helper_curl_easy_setopt(value conn, value option)
3122 CAMLparam2(conn, option);
3123 CAMLlocal1(data);
3124 Connection *connection = Connection_val(conn);
3125 CURLOptionMapping* thisOption = NULL;
3126 static value* exception = NULL;
3128 checkConnection(connection);
3130 data = Field(option, 0);
3132 if (Tag_val(option) < sizeof(implementedOptionMap)/sizeof(CURLOptionMapping))
3134 thisOption = &implementedOptionMap[Tag_val(option)];
3135 if (thisOption->optionHandler)
3137 thisOption->optionHandler(connection, data);
3139 else
3141 if (NULL == exception)
3143 exception = caml_named_value("Curl.NotImplemented");
3144 if (NULL == exception) caml_invalid_argument("Curl.NotImplemented");
3147 caml_raise_with_string(*exception, thisOption->name);
3150 else
3152 caml_failwith("Invalid CURLOPT Option");
3155 CAMLreturn(Val_unit);
3159 ** curl_easy_perform helper function
3162 CAMLprim value helper_curl_easy_perform(value conn)
3164 CAMLparam1(conn);
3165 CURLcode result = CURLE_OK;
3166 Connection *connection = Connection_val(conn);
3168 checkConnection(connection);
3170 caml_enter_blocking_section();
3171 result = curl_easy_perform(connection->handle);
3172 caml_leave_blocking_section();
3174 if (result != CURLE_OK)
3175 raiseError(connection, result);
3177 CAMLreturn(Val_unit);
3181 ** curl_easy_cleanup helper function
3184 CAMLprim value helper_curl_easy_cleanup(value conn)
3186 CAMLparam1(conn);
3187 Connection *connection = Connection_val(conn);
3189 checkConnection(connection);
3191 removeConnection(connection, 0);
3193 CAMLreturn(Val_unit);
3197 ** curl_easy_duphandle helper function
3200 CAMLprim value helper_curl_easy_duphandle(value conn)
3202 CAMLparam1(conn);
3203 CAMLlocal1(result);
3204 Connection *connection = Connection_val(conn);
3206 checkConnection(connection);
3208 result = caml_curl_alloc(duplicateConnection(connection));
3210 CAMLreturn(result);
3214 ** curl_easy_getinfo helper function
3217 enum GetInfoResultType {
3218 StringValue, LongValue, DoubleValue, StringListValue, StringListListValue,
3219 OCamlValue, /* keep last - no matching OCaml CURLINFO_ constructor */
3222 value convertStringList(struct curl_slist *p)
3224 CAMLparam0();
3225 CAMLlocal3(result, current, next);
3227 result = Val_emptylist;
3228 current = Val_emptylist;
3229 next = Val_emptylist;
3231 while (p != NULL)
3233 next = caml_alloc_tuple(2);
3234 Store_field(next, 0, caml_copy_string(p->data));
3235 Store_field(next, 1, Val_emptylist);
3237 if (result == Val_emptylist)
3238 result = next;
3240 if (current != Val_emptylist)
3241 Store_field(current, 1, next);
3243 current = next;
3245 p = p->next;
3248 CAMLreturn(result);
3251 CAMLprim value helper_curl_easy_getinfo(value conn, value option)
3253 CAMLparam2(conn, option);
3254 CAMLlocal3(result, current, next);
3255 CURLcode curlResult;
3256 Connection *connection = Connection_val(conn);
3257 enum GetInfoResultType resultType;
3258 char *strValue = NULL;
3259 double doubleValue;
3260 long longValue;
3261 struct curl_slist *stringListValue = NULL;
3262 #if HAVE_DECL_CURLINFO_CERTINFO
3263 int i;
3264 union {
3265 struct curl_slist *to_info;
3266 struct curl_certinfo *to_certinfo;
3267 } ptr;
3268 #endif
3270 checkConnection(connection);
3272 switch(Long_val(option))
3274 #if HAVE_DECL_CURLINFO_EFFECTIVE_URL
3275 case 0: /* CURLINFO_EFFECTIVE_URL */
3276 resultType = StringValue;
3278 curlResult = curl_easy_getinfo(connection->handle,
3279 CURLINFO_EFFECTIVE_URL,
3280 &strValue);
3281 break;
3282 #else
3283 #pragma message("libcurl does not provide CURLINFO_EFFECTIVE_URL")
3284 #endif
3286 #if HAVE_DECL_CURLINFO_RESPONSE_CODE || HAVE_DECL_CURLINFO_HTTP_CODE
3287 case 1: /* CURLINFO_HTTP_CODE */
3288 case 2: /* CURLINFO_RESPONSE_CODE */
3289 #if HAVE_DECL_CURLINFO_RESPONSE_CODE
3290 resultType = LongValue;
3292 curlResult = curl_easy_getinfo(connection->handle,
3293 CURLINFO_RESPONSE_CODE,
3294 &longValue);
3295 #else
3296 resultType = LongValue;
3298 curlResult = curl_easy_getinfo(connection->handle,
3299 CURLINFO_HTTP_CODE,
3300 &longValue);
3301 #endif
3302 break;
3303 #endif
3305 #if HAVE_DECL_CURLINFO_TOTAL_TIME
3306 case 3: /* CURLINFO_TOTAL_TIME */
3307 resultType = DoubleValue;
3309 curlResult = curl_easy_getinfo(connection->handle,
3310 CURLINFO_TOTAL_TIME,
3311 &doubleValue);
3312 break;
3313 #endif
3315 #if HAVE_DECL_CURLINFO_NAMELOOKUP_TIME
3316 case 4: /* CURLINFO_NAMELOOKUP_TIME */
3317 resultType = DoubleValue;
3319 curlResult = curl_easy_getinfo(connection->handle,
3320 CURLINFO_NAMELOOKUP_TIME,
3321 &doubleValue);
3322 break;
3323 #endif
3325 #if HAVE_DECL_CURLINFO_CONNECT_TIME
3326 case 5: /* CURLINFO_CONNECT_TIME */
3327 resultType = DoubleValue;
3329 curlResult = curl_easy_getinfo(connection->handle,
3330 CURLINFO_CONNECT_TIME,
3331 &doubleValue);
3332 break;
3333 #endif
3335 #if HAVE_DECL_CURLINFO_PRETRANSFER_TIME
3336 case 6: /* CURLINFO_PRETRANSFER_TIME */
3337 resultType = DoubleValue;
3339 curlResult = curl_easy_getinfo(connection->handle,
3340 CURLINFO_PRETRANSFER_TIME,
3341 &doubleValue);
3342 break;
3343 #endif
3345 #if HAVE_DECL_CURLINFO_SIZE_UPLOAD
3346 case 7: /* CURLINFO_SIZE_UPLOAD */
3347 resultType = DoubleValue;
3349 curlResult = curl_easy_getinfo(connection->handle,
3350 CURLINFO_SIZE_UPLOAD,
3351 &doubleValue);
3352 break;
3353 #endif
3355 #if HAVE_DECL_CURLINFO_SIZE_DOWNLOAD
3356 case 8: /* CURLINFO_SIZE_DOWNLOAD */
3357 resultType = DoubleValue;
3359 curlResult = curl_easy_getinfo(connection->handle,
3360 CURLINFO_SIZE_DOWNLOAD,
3361 &doubleValue);
3362 break;
3363 #endif
3365 #if HAVE_DECL_CURLINFO_SPEED_DOWNLOAD
3366 case 9: /* CURLINFO_SPEED_DOWNLOAD */
3367 resultType = DoubleValue;
3369 curlResult = curl_easy_getinfo(connection->handle,
3370 CURLINFO_SPEED_DOWNLOAD,
3371 &doubleValue);
3372 break;
3373 #endif
3375 #if HAVE_DECL_CURLINFO_SPEED_UPLOAD
3376 case 10: /* CURLINFO_SPEED_UPLOAD */
3377 resultType = DoubleValue;
3379 curlResult = curl_easy_getinfo(connection->handle,
3380 CURLINFO_SPEED_UPLOAD,
3381 &doubleValue);
3382 break;
3384 #endif
3386 #if HAVE_DECL_CURLINFO_HEADER_SIZE
3387 case 11: /* CURLINFO_HEADER_SIZE */
3388 resultType = LongValue;
3390 curlResult = curl_easy_getinfo(connection->handle,
3391 CURLINFO_HEADER_SIZE,
3392 &longValue);
3393 break;
3394 #endif
3396 #if HAVE_DECL_CURLINFO_REQUEST_SIZE
3397 case 12: /* CURLINFO_REQUEST_SIZE */
3398 resultType = LongValue;
3400 curlResult = curl_easy_getinfo(connection->handle,
3401 CURLINFO_REQUEST_SIZE,
3402 &longValue);
3403 break;
3404 #endif
3406 #if HAVE_DECL_CURLINFO_SSL_VERIFYRESULT
3407 case 13: /* CURLINFO_SSL_VERIFYRESULT */
3408 resultType = LongValue;
3410 curlResult = curl_easy_getinfo(connection->handle,
3411 CURLINFO_SSL_VERIFYRESULT,
3412 &longValue);
3413 break;
3414 #endif
3416 #if HAVE_DECL_CURLINFO_FILETIME
3417 case 14: /* CURLINFO_FILETIME */
3418 resultType = DoubleValue;
3420 curlResult = curl_easy_getinfo(connection->handle,
3421 CURLINFO_FILETIME,
3422 &longValue);
3424 doubleValue = longValue;
3425 break;
3426 #endif
3428 #if HAVE_DECL_CURLINFO_CONTENT_LENGTH_DOWNLOAD
3429 case 15: /* CURLINFO_CONTENT_LENGTH_DOWNLOAD */
3430 resultType = DoubleValue;
3432 curlResult = curl_easy_getinfo(connection->handle,
3433 CURLINFO_CONTENT_LENGTH_DOWNLOAD,
3434 &doubleValue);
3435 break;
3436 #endif
3438 #if HAVE_DECL_CURLINFO_CONTENT_LENGTH_UPLOAD
3439 case 16: /* CURLINFO_CONTENT_LENGTH_UPLOAD */
3440 resultType = DoubleValue;
3442 curlResult = curl_easy_getinfo(connection->handle,
3443 CURLINFO_CONTENT_LENGTH_UPLOAD,
3444 &doubleValue);
3445 break;
3446 #endif
3448 #if HAVE_DECL_CURLINFO_STARTTRANSFER_TIME
3449 case 17: /* CURLINFO_STARTTRANSFER_TIME */
3450 resultType = DoubleValue;
3452 curlResult = curl_easy_getinfo(connection->handle,
3453 CURLINFO_STARTTRANSFER_TIME,
3454 &doubleValue);
3455 break;
3456 #endif
3458 #if HAVE_DECL_CURLINFO_CONTENT_TYPE
3459 case 18: /* CURLINFO_CONTENT_TYPE */
3460 resultType = StringValue;
3462 curlResult = curl_easy_getinfo(connection->handle,
3463 CURLINFO_CONTENT_TYPE,
3464 &strValue);
3465 break;
3466 #endif
3468 #if HAVE_DECL_CURLINFO_REDIRECT_TIME
3469 case 19: /* CURLINFO_REDIRECT_TIME */
3470 resultType = DoubleValue;
3472 curlResult = curl_easy_getinfo(connection->handle,
3473 CURLINFO_REDIRECT_TIME,
3474 &doubleValue);
3475 break;
3476 #endif
3478 #if HAVE_DECL_CURLINFO_REDIRECT_COUNT
3479 case 20: /* CURLINFO_REDIRECT_COUNT */
3480 resultType = LongValue;
3482 curlResult = curl_easy_getinfo(connection->handle,
3483 CURLINFO_REDIRECT_COUNT,
3484 &longValue);
3485 break;
3486 #endif
3488 case 21: /* CURLINFO_PRIVATE */
3489 resultType = OCamlValue;
3490 curlResult = CURLE_OK;
3491 result = caml_alloc(1, StringValue);
3492 Store_field(result, 0, Field(connection->ocamlValues, Ocaml_PRIVATE));
3493 break;
3495 #if HAVE_DECL_CURLINFO_HTTP_CONNECTCODE
3496 case 22: /* CURLINFO_HTTP_CONNECTCODE */
3497 resultType = LongValue;
3499 curlResult = curl_easy_getinfo(connection->handle,
3500 CURLINFO_HTTP_CONNECTCODE,
3501 &longValue);
3502 break;
3503 #endif
3505 #if HAVE_DECL_CURLINFO_HTTPAUTH_AVAIL
3506 case 23: /* CURLINFO_HTTPAUTH_AVAIL */
3507 resultType = LongValue;
3509 curlResult = curl_easy_getinfo(connection->handle,
3510 CURLINFO_HTTPAUTH_AVAIL,
3511 &longValue);
3512 break;
3513 #endif
3515 #if HAVE_DECL_CURLINFO_PROXYAUTH_AVAIL
3516 case 24: /* CURLINFO_PROXYAUTH_AVAIL */
3517 resultType = LongValue;
3519 curlResult = curl_easy_getinfo(connection->handle,
3520 CURLINFO_PROXYAUTH_AVAIL,
3521 &longValue);
3522 break;
3523 #endif
3525 #if HAVE_DECL_CURLINFO_OS_ERRNO
3526 case 25: /* CURLINFO_OS_ERRNO */
3527 resultType = LongValue;
3529 curlResult = curl_easy_getinfo(connection->handle,
3530 CURLINFO_OS_ERRNO,
3531 &longValue);
3532 break;
3533 #endif
3535 #if HAVE_DECL_CURLINFO_NUM_CONNECTS
3536 case 26: /* CURLINFO_NUM_CONNECTS */
3537 resultType = LongValue;
3539 curlResult = curl_easy_getinfo(connection->handle,
3540 CURLINFO_NUM_CONNECTS,
3541 &longValue);
3542 break;
3543 #endif
3545 #if HAVE_DECL_CURLINFO_SSL_ENGINES
3546 case 27: /* CURLINFO_SSL_ENGINES */
3547 resultType = StringListValue;
3549 curlResult = curl_easy_getinfo(connection->handle,
3550 CURLINFO_SSL_ENGINES,
3551 &stringListValue);
3552 break;
3553 #endif
3555 #if HAVE_DECL_CURLINFO_COOKIELIST
3556 case 28: /* CURLINFO_COOKIELIST */
3557 resultType = StringListValue;
3559 curlResult = curl_easy_getinfo(connection->handle,
3560 CURLINFO_COOKIELIST,
3561 &stringListValue);
3562 break;
3563 #endif
3565 #if HAVE_DECL_CURLINFO_LASTSOCKET
3566 case 29: /* CURLINFO_LASTSOCKET */
3567 resultType = LongValue;
3569 curlResult = curl_easy_getinfo(connection->handle,
3570 CURLINFO_LASTSOCKET,
3571 &longValue);
3572 break;
3573 #endif
3575 #if HAVE_DECL_CURLINFO_FTP_ENTRY_PATH
3576 case 30: /* CURLINFO_FTP_ENTRY_PATH */
3577 resultType = StringValue;
3579 curlResult = curl_easy_getinfo(connection->handle,
3580 CURLINFO_FTP_ENTRY_PATH,
3581 &strValue);
3582 break;
3583 #endif
3585 #if HAVE_DECL_CURLINFO_REDIRECT_URL
3586 case 31: /* CURLINFO_REDIRECT_URL */
3587 resultType = StringValue;
3589 curlResult = curl_easy_getinfo(connection->handle,
3590 CURLINFO_REDIRECT_URL,
3591 &strValue);
3592 break;
3593 #else
3594 #pragma message("libcurl does not provide CURLINFO_REDIRECT_URL")
3595 #endif
3597 #if HAVE_DECL_CURLINFO_PRIMARY_IP
3598 case 32: /* CURLINFO_PRIMARY_IP */
3599 resultType = StringValue;
3601 curlResult = curl_easy_getinfo(connection->handle,
3602 CURLINFO_PRIMARY_IP,
3603 &strValue);
3604 break;
3605 #else
3606 #pragma message("libcurl does not provide CURLINFO_PRIMARY_IP")
3607 #endif
3609 #if HAVE_DECL_CURLINFO_LOCAL_IP
3610 case 33: /* CURLINFO_LOCAL_IP */
3611 resultType = StringValue;
3613 curlResult = curl_easy_getinfo(connection->handle,
3614 CURLINFO_LOCAL_IP,
3615 &strValue);
3616 break;
3617 #else
3618 #pragma message("libcurl does not provide CURLINFO_LOCAL_IP")
3619 #endif
3621 #if HAVE_DECL_CURLINFO_LOCAL_PORT
3622 case 34: /* CURLINFO_LOCAL_PORT */
3623 resultType = LongValue;
3625 curlResult = curl_easy_getinfo(connection->handle,
3626 CURLINFO_LOCAL_PORT,
3627 &longValue);
3628 break;
3629 #else
3630 #pragma message("libcurl does not provide CURLINFO_LOCAL_PORT")
3631 #endif
3633 #if HAVE_DECL_CURLINFO_CONDITION_UNMET
3634 case 35: /* CURLINFO_CONDITION_UNMET */
3635 resultType = LongValue;
3637 curlResult = curl_easy_getinfo(connection->handle,
3638 CURLINFO_CONDITION_UNMET,
3639 &longValue);
3640 break;
3641 #else
3642 #pragma message("libcurl does not provide CURLINFO_CONDITION_UNMET")
3643 #endif
3644 #if HAVE_DECL_CURLINFO_CERTINFO
3645 case 36: /* CURLINFO_CERTINFO */
3646 resultType = StringListListValue;
3647 ptr.to_info = NULL;
3648 curlResult = curl_easy_getinfo(connection->handle,
3649 CURLINFO_CERTINFO,
3650 &ptr.to_info);
3652 result = Val_emptylist;
3653 current = Val_emptylist;
3654 next = Val_emptylist;
3656 if (curlResult != CURLE_OK || !ptr.to_info)
3657 break;
3659 for (i = 0; i < ptr.to_certinfo->num_of_certs; i++) {
3660 next = caml_alloc_tuple(2);
3661 Store_field(next, 0, convertStringList(ptr.to_certinfo->certinfo[i]));
3662 Store_field(next, 1, current);
3663 current = next;
3665 break;
3666 #else
3667 #pragma message("libcurl does not provide CURLINFO_CERTINFO")
3668 #endif
3669 default:
3670 caml_failwith("Invalid CURLINFO Option");
3671 break;
3674 if (curlResult != CURLE_OK)
3675 raiseError(connection, curlResult);
3677 switch (resultType)
3679 case StringValue:
3680 result = caml_alloc(1, StringValue);
3681 Store_field(result, 0, caml_copy_string(strValue?strValue:""));
3682 break;
3684 case LongValue:
3685 result = caml_alloc(1, LongValue);
3686 Store_field(result, 0, Val_long(longValue));
3687 break;
3689 case DoubleValue:
3690 result = caml_alloc(1, DoubleValue);
3691 Store_field(result, 0, caml_copy_double(doubleValue));
3692 break;
3694 case StringListValue:
3695 result = caml_alloc(1, StringListValue);
3696 Store_field(result, 0, convertStringList(stringListValue));
3697 curl_slist_free_all(stringListValue);
3698 break;
3700 case StringListListValue:
3701 result = caml_alloc(1, StringListListValue);
3702 Store_field(result, 0, current);
3703 break;
3705 case OCamlValue:
3706 break;
3709 CAMLreturn(result);
3713 ** curl_escape helper function
3716 CAMLprim value helper_curl_escape(value str)
3718 CAMLparam1(str);
3719 CAMLlocal1(result);
3720 char *curlResult;
3722 curlResult = curl_escape(String_val(str), caml_string_length(str));
3723 result = caml_copy_string(curlResult);
3724 free(curlResult);
3726 CAMLreturn(result);
3730 ** curl_unescape helper function
3733 CAMLprim value helper_curl_unescape(value str)
3735 CAMLparam1(str);
3736 CAMLlocal1(result);
3737 char *curlResult;
3739 curlResult = curl_unescape(String_val(str), caml_string_length(str));
3740 result = caml_copy_string(curlResult);
3741 free(curlResult);
3743 CAMLreturn(result);
3747 ** curl_getdate helper function
3750 CAMLprim value helper_curl_getdate(value str, value now)
3752 CAMLparam2(str, now);
3753 CAMLlocal1(result);
3754 time_t curlResult;
3755 time_t curlNow;
3757 curlNow = (time_t)Double_val(now);
3758 curlResult = curl_getdate(String_val(str), &curlNow);
3759 result = caml_copy_double((double)curlResult);
3761 CAMLreturn(result);
3765 ** curl_version helper function
3768 CAMLprim value helper_curl_version(void)
3770 CAMLparam0();
3771 CAMLlocal1(result);
3772 char *str;
3774 str = curl_version();
3775 result = caml_copy_string(str);
3777 CAMLreturn(result);
3780 struct CURLVersionBitsMapping
3782 int code;
3783 char *name;
3786 struct CURLVersionBitsMapping versionBitsMap[] =
3788 {CURL_VERSION_IPV6, "ipv6"},
3789 {CURL_VERSION_KERBEROS4, "kerberos4"},
3790 {CURL_VERSION_SSL, "ssl"},
3791 {CURL_VERSION_LIBZ, "libz"},
3792 {CURL_VERSION_NTLM, "ntlm"},
3793 {CURL_VERSION_GSSNEGOTIATE, "gssnegotiate"},
3794 {CURL_VERSION_DEBUG, "debug"},
3795 {CURL_VERSION_CURLDEBUG, "curldebug"},
3796 {CURL_VERSION_ASYNCHDNS, "asynchdns"},
3797 {CURL_VERSION_SPNEGO, "spnego"},
3798 {CURL_VERSION_LARGEFILE, "largefile"},
3799 {CURL_VERSION_IDN, "idn"},
3800 {CURL_VERSION_SSPI, "sspi"},
3801 {CURL_VERSION_CONV, "conv"},
3802 #if HAVE_DECL_CURL_VERSION_TLSAUTH_SRP
3803 {CURL_VERSION_TLSAUTH_SRP, "srp"},
3804 #endif
3805 #if HAVE_DECL_CURL_VERSION_NTLM_WB
3806 {CURL_VERSION_NTLM_WB, "wb"},
3807 #endif
3810 CAMLprim value caml_curl_version_info(value unit)
3812 CAMLparam1(unit);
3813 CAMLlocal4(v, vlist, vnum, vfeatures);
3814 const char* const* p = NULL;
3815 size_t i = 0;
3817 curl_version_info_data* data = curl_version_info(CURLVERSION_NOW);
3818 if (NULL == data) caml_failwith("curl_version_info");
3820 vlist = Val_emptylist;
3821 for (p = data->protocols; NULL != *p; p++)
3823 vlist = Val_cons(vlist, caml_copy_string(*p));
3826 vfeatures = Val_emptylist;
3827 for (i = 0; i < sizeof(versionBitsMap)/sizeof(versionBitsMap[0]); i++)
3829 if (0 != (versionBitsMap[i].code & data->features))
3830 vfeatures = Val_cons(vfeatures, caml_copy_string(versionBitsMap[i].name));
3833 vnum = caml_alloc_tuple(3);
3834 Store_field(vnum,0,Val_int(0xFF & (data->version_num >> 16)));
3835 Store_field(vnum,1,Val_int(0xFF & (data->version_num >> 8)));
3836 Store_field(vnum,2,Val_int(0xFF & (data->version_num)));
3838 v = caml_alloc_tuple(12);
3839 Store_field(v,0,caml_copy_string(data->version));
3840 Store_field(v,1,vnum);
3841 Store_field(v,2,caml_copy_string(data->host));
3842 Store_field(v,3,vfeatures);
3843 Store_field(v,4,data->ssl_version ? Val_some(caml_copy_string(data->ssl_version)) : Val_none);
3844 Store_field(v,5,data->libz_version ? Val_some(caml_copy_string(data->libz_version)) : Val_none);
3845 Store_field(v,6,vlist);
3846 Store_field(v,7,caml_copy_string((data->age >= 1 && data->ares) ? data->ares : ""));
3847 Store_field(v,8,Val_int((data->age >= 1) ? data->ares_num : 0));
3848 Store_field(v,9,caml_copy_string((data->age >= 2 && data->libidn) ? data->libidn : ""));
3849 Store_field(v,10,Val_int((data->age >= 3) ? data->iconv_ver_num : 0));
3850 Store_field(v,11,caml_copy_string((data->age >= 3 && data->libssh_version) ? data->libssh_version : ""));
3852 CAMLreturn(v);
3855 CAMLprim value caml_curl_pause(value conn, value opts)
3857 CAMLparam2(conn, opts);
3858 CAMLlocal4(v, vlist, vnum, vfeatures);
3859 Connection *connection = Connection_val(conn);
3860 int bitmask = 0;
3861 CURLcode result;
3863 while (Val_emptylist != opts)
3865 switch (Int_val(Field(opts,0)))
3867 case 0: bitmask |= CURLPAUSE_SEND; break;
3868 case 1: bitmask |= CURLPAUSE_RECV; break;
3869 case 2: bitmask |= CURLPAUSE_ALL; break;
3870 default: caml_failwith("wrong pauseOption");
3872 opts = Field(opts,1);
3875 result = curl_easy_pause(connection->handle,bitmask);
3876 if (result != CURLE_OK)
3877 raiseError(connection, result);
3879 CAMLreturn(Val_unit);
3883 * Curl multi stack support
3885 * Exported thin wrappers for libcurl are prefixed with caml_curl_multi_.
3886 * Other exported functions are prefixed with caml_curlm_, some of them
3887 * can/should be decomposed into smaller parts.
3890 struct ml_multi_handle
3892 CURLM* handle;
3893 value values; /* callbacks */
3896 enum
3898 curlmopt_socket_function,
3899 curlmopt_timer_function,
3901 /* last, not used */
3902 multi_values_total
3905 typedef struct ml_multi_handle ml_multi_handle;
3907 #define Multi_val(v) (*(ml_multi_handle**)Data_custom_val(v))
3908 #define CURLM_val(v) (Multi_val(v)->handle)
3910 static struct custom_operations curl_multi_ops = {
3911 "ygrek.curl_multi",
3912 custom_finalize_default,
3913 custom_compare_default,
3914 custom_hash_default,
3915 custom_serialize_default,
3916 custom_deserialize_default,
3917 #if defined(custom_compare_ext_default)
3918 custom_compare_ext_default,
3919 #endif
3922 CAMLprim value caml_curl_multi_init(value unit)
3924 CAMLparam1(unit);
3925 CAMLlocal1(v);
3926 ml_multi_handle* multi = (ml_multi_handle*)caml_stat_alloc(sizeof(ml_multi_handle));
3927 CURLM* h = curl_multi_init();
3929 if (!h)
3931 caml_stat_free(multi);
3932 caml_failwith("caml_curl_multi_init");
3935 multi->handle = h;
3936 multi->values = caml_alloc(multi_values_total, 0);
3937 caml_register_generational_global_root(&multi->values);
3939 v = caml_alloc_custom(&curl_multi_ops, sizeof(ml_multi_handle*), 0, 1);
3940 Multi_val(v) = multi;
3942 CAMLreturn(v);
3945 CAMLprim value caml_curl_multi_cleanup(value handle)
3947 CAMLparam1(handle);
3948 ml_multi_handle* h = Multi_val(handle);
3950 if (NULL == h)
3951 CAMLreturn(Val_unit);
3953 caml_remove_generational_global_root(&h->values);
3955 if (CURLM_OK != curl_multi_cleanup(h->handle))
3956 caml_failwith("caml_curl_multi_cleanup");
3958 caml_stat_free(h);
3959 Multi_val(handle) = (ml_multi_handle*)NULL;
3961 CAMLreturn(Val_unit);
3964 static CURL* curlm_remove_finished(CURLM* multi_handle, CURLcode* result)
3966 int msgs_in_queue = 0;
3968 while (1)
3970 CURLMsg* msg = curl_multi_info_read(multi_handle, &msgs_in_queue);
3971 if (NULL == msg) return NULL;
3972 if (CURLMSG_DONE == msg->msg)
3974 CURL* easy_handle = msg->easy_handle;
3975 if (result) *result = msg->data.result;
3976 if (CURLM_OK != curl_multi_remove_handle(multi_handle, easy_handle))
3978 /*caml_failwith("curlm_remove_finished");*/
3980 return easy_handle;
3985 CAMLprim value caml_curlm_remove_finished(value v_multi)
3987 CAMLparam1(v_multi);
3988 CAMLlocal2(v_easy, v_tuple);
3989 CURL* handle;
3990 CURLM* multi_handle;
3991 CURLcode result;
3992 Connection* conn = NULL;
3994 multi_handle = CURLM_val(v_multi);
3996 caml_enter_blocking_section();
3997 handle = curlm_remove_finished(multi_handle,&result);
3998 caml_leave_blocking_section();
4000 if (NULL == handle)
4002 CAMLreturn(Val_none);
4004 else
4006 conn = getConnection(handle);
4007 if (conn->curl_ERRORBUFFER != NULL)
4009 Store_field(Field(conn->ocamlValues, Ocaml_ERRORBUFFER), 0, caml_copy_string(conn->curl_ERRORBUFFER));
4011 conn->refcount--;
4012 /* NB: same handle, but different block */
4013 v_easy = caml_curl_alloc(conn);
4014 v_tuple = caml_alloc(2, 0);
4015 Store_field(v_tuple,0,v_easy);
4016 Store_field(v_tuple,1,Val_int(result)); /* CURLcode */
4017 CAMLreturn(Val_some(v_tuple));
4021 static int curlm_wait_data(CURLM* multi_handle)
4023 struct timeval timeout;
4024 CURLMcode ret;
4026 fd_set fdread;
4027 fd_set fdwrite;
4028 fd_set fdexcep;
4029 int maxfd = -1;
4031 FD_ZERO(&fdread);
4032 FD_ZERO(&fdwrite);
4033 FD_ZERO(&fdexcep);
4035 /* set a suitable timeout */
4036 timeout.tv_sec = 1;
4037 timeout.tv_usec = 0;
4039 /* get file descriptors from the transfers */
4040 ret = curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
4042 if (ret == CURLM_OK && maxfd >= 0)
4044 int rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
4045 if (-1 != rc) return 0;
4047 return 1;
4050 CAMLprim value caml_curlm_wait_data(value v_multi)
4052 CAMLparam1(v_multi);
4053 int ret;
4054 CURLM* h = CURLM_val(v_multi);
4056 caml_enter_blocking_section();
4057 ret = curlm_wait_data(h);
4058 caml_leave_blocking_section();
4060 CAMLreturn(Val_bool(0 == ret));
4063 CAMLprim value caml_curl_multi_add_handle(value v_multi, value v_easy)
4065 CAMLparam2(v_multi,v_easy);
4066 CURLM* multi = CURLM_val(v_multi);
4067 Connection* conn = Connection_val(v_easy);
4069 /* prevent collection of OCaml value while the easy handle is used
4070 and may invoke callbacks registered on OCaml side */
4071 conn->refcount++;
4073 /* may invoke callbacks so need to be consistent with locks */
4074 caml_enter_blocking_section();
4075 if (CURLM_OK != curl_multi_add_handle(multi, conn->handle))
4077 conn->refcount--; /* not added, revert */
4078 caml_leave_blocking_section();
4079 caml_failwith("caml_curl_multi_add_handle");
4081 caml_leave_blocking_section();
4083 CAMLreturn(Val_unit);
4086 CAMLprim value caml_curl_multi_remove_handle(value v_multi, value v_easy)
4088 CAMLparam2(v_multi,v_easy);
4089 CURLM* multi = CURLM_val(v_multi);
4090 Connection* conn = Connection_val(v_easy);
4092 /* may invoke callbacks so need to be consistent with locks */
4093 caml_enter_blocking_section();
4094 if (CURLM_OK != curl_multi_remove_handle(multi, conn->handle))
4096 caml_leave_blocking_section();
4097 caml_failwith("caml_curl_multi_remove_handle");
4099 conn->refcount--;
4100 caml_leave_blocking_section();
4102 CAMLreturn(Val_unit);
4105 CAMLprim value caml_curl_multi_perform_all(value v_multi)
4107 CAMLparam1(v_multi);
4108 int still_running = 0;
4109 CURLM* h = CURLM_val(v_multi);
4111 caml_enter_blocking_section();
4112 while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(h, &still_running));
4113 caml_leave_blocking_section();
4115 CAMLreturn(Val_int(still_running));
4118 CAMLprim value helper_curl_easy_strerror(value v_code)
4120 CAMLparam1(v_code);
4121 CAMLreturn(caml_copy_string(curl_easy_strerror((CURLcode)Int_val(v_code))));
4125 * Wrappers for the curl_multi_socket_action infrastructure
4126 * Based on curl hiperfifo.c example
4129 #ifdef _WIN32
4130 #ifndef Val_socket
4131 #define Val_socket(v) win_alloc_socket(v)
4132 #endif
4133 #ifndef Socket_val
4134 #error Socket_val not defined in unixsupport.h
4135 #endif
4136 #else /* _WIN32 */
4137 #ifndef Socket_val
4138 #define Socket_val(v) Long_val(v)
4139 #endif
4140 #ifndef Val_socket
4141 #define Val_socket(v) Val_int(v)
4142 #endif
4143 #endif /* _WIN32 */
4145 static void raise_multi_error(char const* msg)
4147 static value* exception = NULL;
4149 if (NULL == exception)
4151 exception = caml_named_value("Curl.Multi.Error");
4152 if (NULL == exception) caml_invalid_argument("Curl.Multi.Error");
4155 caml_raise_with_string(*exception, msg);
4158 static void check_mcode(CURLMcode code)
4160 char const *s = NULL;
4161 switch (code)
4163 case CURLM_OK : return;
4164 case CURLM_CALL_MULTI_PERFORM : s="CURLM_CALL_MULTI_PERFORM"; break;
4165 case CURLM_BAD_HANDLE : s="CURLM_BAD_HANDLE"; break;
4166 case CURLM_BAD_EASY_HANDLE : s="CURLM_BAD_EASY_HANDLE"; break;
4167 case CURLM_OUT_OF_MEMORY : s="CURLM_OUT_OF_MEMORY"; break;
4168 case CURLM_INTERNAL_ERROR : s="CURLM_INTERNAL_ERROR"; break;
4169 case CURLM_UNKNOWN_OPTION : s="CURLM_UNKNOWN_OPTION"; break;
4170 case CURLM_LAST : s="CURLM_LAST"; break;
4171 case CURLM_BAD_SOCKET : s="CURLM_BAD_SOCKET"; break;
4172 default : s="CURLM_unknown"; break;
4174 raise_multi_error(s);
4177 CAMLprim value caml_curl_multi_socket_action(value v_multi, value v_fd, value v_kind)
4179 CAMLparam3(v_multi, v_fd, v_kind);
4180 CURLM* h = CURLM_val(v_multi);
4181 int still_running = 0;
4182 CURLMcode rc = CURLM_OK;
4183 curl_socket_t socket;
4184 int kind = 0;
4186 if (Val_none == v_fd)
4188 socket = CURL_SOCKET_TIMEOUT;
4190 else
4192 socket = Socket_val(Field(v_fd, 0));
4195 switch (Int_val(v_kind))
4197 case 0 : break;
4198 case 1 : kind |= CURL_CSELECT_IN; break;
4199 case 2 : kind |= CURL_CSELECT_OUT; break;
4200 case 3 : kind |= CURL_CSELECT_IN | CURL_CSELECT_OUT; break;
4201 default:
4202 raise_multi_error("caml_curl_multi_socket_action");
4205 /* fprintf(stdout,"fd %u kind %u\n",socket, kind); fflush(stdout); */
4207 caml_enter_blocking_section();
4208 do {
4209 rc = curl_multi_socket_action(h, socket, kind, &still_running);
4210 } while (rc == CURLM_CALL_MULTI_PERFORM);
4211 caml_leave_blocking_section();
4213 check_mcode(rc);
4215 CAMLreturn(Val_int(still_running));
4218 CAMLprim value caml_curl_multi_socket_all(value v_multi)
4220 CAMLparam1(v_multi);
4221 int still_running = 0;
4222 CURLMcode rc = CURLM_OK;
4223 CURLM* h = CURLM_val(v_multi);
4225 caml_enter_blocking_section();
4226 do {
4227 rc = curl_multi_socket_all(h, &still_running);
4228 } while (rc == CURLM_CALL_MULTI_PERFORM);
4229 caml_leave_blocking_section();
4231 check_mcode(rc);
4233 CAMLreturn(Val_int(still_running));
4236 static int curlm_sock_cb(CURL *e, curl_socket_t sock, int what, void *cbp, void *sockp)
4238 caml_leave_blocking_section();
4240 CAMLparam0();
4241 CAMLlocal2(v_what,csock);
4242 (void)e;
4243 (void)sockp; /* not used */
4245 /* v_what = Val_int(what); */
4246 switch (what)
4248 case CURL_POLL_NONE : v_what = Val_int(0); break;
4249 case CURL_POLL_IN : v_what = Val_int(1); break;
4250 case CURL_POLL_OUT : v_what = Val_int(2); break;
4251 case CURL_POLL_INOUT : v_what = Val_int(3); break;
4252 case CURL_POLL_REMOVE : v_what = Val_int(4); break;
4253 default:
4254 fprintf(stderr, "curlm_sock_cb sock=%d what=%d\n", sock, what);
4255 fflush(stderr);
4256 raise_multi_error("curlm_sock_cb"); /* FIXME exception from callback */
4258 csock=Val_socket(sock);
4259 caml_callback2(Field(((ml_multi_handle*)cbp)->values,curlmopt_socket_function),
4260 csock, v_what);
4261 CAMLdrop;
4263 caml_enter_blocking_section();
4264 return 0;
4267 CAMLprim value caml_curl_multi_socketfunction(value v_multi, value v_cb)
4269 CAMLparam2(v_multi, v_cb);
4270 ml_multi_handle* multi = Multi_val(v_multi);
4272 Store_field(multi->values, curlmopt_socket_function, v_cb);
4274 curl_multi_setopt(multi->handle, CURLMOPT_SOCKETFUNCTION, curlm_sock_cb);
4275 curl_multi_setopt(multi->handle, CURLMOPT_SOCKETDATA, multi);
4277 CAMLreturn(Val_unit);
4280 static int curlm_timer_cb(CURLM *multi, long timeout_ms, void *userp)
4282 caml_leave_blocking_section();
4284 CAMLparam0();
4285 (void)multi;
4286 caml_callback(Field(((ml_multi_handle*)userp)->values,curlmopt_timer_function), Val_long(timeout_ms));
4287 CAMLdrop;
4289 caml_enter_blocking_section();
4290 return 0;
4293 CAMLprim value caml_curl_multi_timerfunction(value v_multi, value v_cb)
4295 CAMLparam2(v_multi, v_cb);
4296 ml_multi_handle* multi = Multi_val(v_multi);
4298 Store_field(multi->values, curlmopt_timer_function, v_cb);
4300 curl_multi_setopt(multi->handle, CURLMOPT_TIMERFUNCTION, curlm_timer_cb);
4301 curl_multi_setopt(multi->handle, CURLMOPT_TIMERDATA, multi);
4303 CAMLreturn(Val_unit);
4306 CAMLprim value caml_curl_multi_timeout(value v_multi)
4308 CAMLparam1(v_multi);
4309 long ms = 0;
4310 CURLMcode rc = CURLM_OK;
4311 ml_multi_handle* multi = Multi_val(v_multi);
4313 rc = curl_multi_timeout(multi->handle, &ms);
4315 check_mcode(rc);
4317 CAMLreturn(Val_long(ms));
4320 #define SETMOPT_VAL_(func_name, curl_option, conv_val) \
4321 static void func_name(CURLM *handle, value option) \
4323 CAMLparam1(option); \
4324 CURLMcode result = CURLM_OK; \
4326 result = curl_multi_setopt(handle, curl_option, conv_val(option)); \
4328 check_mcode(result); \
4330 CAMLreturn0; \
4333 #define SETMOPT_VAL(name, conv) SETMOPT_VAL_(handle_multi_##name, CURLMOPT_##name, conv)
4334 #define SETMOPT_BOOL(name) SETMOPT_VAL(name, Bool_val)
4335 #define SETMOPT_LONG(name) SETMOPT_VAL(name, Long_val)
4336 #define SETMOPT_INT64(name) SETMOPT_VAL(name, Int64_val)
4338 long pipeliningMap[] =
4340 0, /* CURLPIPE_NOTHING */
4341 1, /* CURLPIPE_HTTP1 */
4342 2, /* CURLPIPE_MULTIPLEX */
4345 static void handle_multi_PIPELINING(CURLM* handle, value option)
4347 CAMLparam1(option);
4348 CURLMcode result = CURLM_OK;
4350 long bits = convert_bit_list(pipeliningMap, sizeof(pipeliningMap) / sizeof(pipeliningMap[0]), option);
4352 result = curl_multi_setopt(handle, CURLMOPT_PIPELINING, bits);
4354 check_mcode(result);
4356 CAMLreturn0;
4359 #if HAVE_DECL_CURLMOPT_MAXCONNECTS
4360 SETMOPT_LONG( MAXCONNECTS)
4361 #endif
4363 #if HAVE_DECL_CURLMOPT_MAX_PIPELINE_LENGTH
4364 SETMOPT_LONG( MAX_PIPELINE_LENGTH)
4365 #endif
4367 #if HAVE_DECL_CURLMOPT_MAX_HOST_CONNECTIONS
4368 SETMOPT_LONG( MAX_HOST_CONNECTIONS)
4369 #endif
4371 typedef struct CURLMOptionMapping CURLMOptionMapping;
4372 #define OPT(name) { handle_multi_## name, "CURLMOPT_"#name}
4373 #define NO_OPT(name) { NULL, "CURLMOPT_"#name}
4375 struct CURLMOptionMapping
4377 void (*optionHandler)(CURLM *, value);
4378 char *name;
4381 CURLMOptionMapping implementedMOptionMap[] = {
4382 OPT( PIPELINING),
4383 #if HAVE_DECL_CURLMOPT_MAXCONNECTS
4384 OPT( MAXCONNECTS),
4385 #else
4386 NO_OPT( MAXCONNECTS),
4387 #endif
4388 #if HAVE_DECL_CURLMOPT_MAX_PIPELINE_LENGTH
4389 OPT( MAX_PIPELINE_LENGTH),
4390 #else
4391 NO_OPT( MAX_PIPELINE_LENGTH),
4392 #endif
4393 #if HAVE_DECL_CURLMOPT_MAX_HOST_CONNECTIONS
4394 OPT( MAX_HOST_CONNECTIONS),
4395 #else
4396 NO_OPT( MAX_HOST_CONNECTIONS),
4397 #endif
4400 CAMLprim value caml_curl_multi_setopt(value v_multi, value option)
4402 CAMLparam2(v_multi, option);
4403 CAMLlocal1(data);
4404 CURLM *handle = Multi_val(v_multi)->handle;
4405 CURLMOptionMapping* thisOption = NULL;
4406 static value* exception = NULL;
4408 data = Field(option, 0);
4410 if (Tag_val(option) < sizeof(implementedMOptionMap)/sizeof(CURLMOptionMapping))
4412 thisOption = &implementedMOptionMap[Tag_val(option)];
4413 if (thisOption->optionHandler)
4415 thisOption->optionHandler(handle, data);
4417 else
4419 if (NULL == exception)
4421 exception = caml_named_value("Curl.NotImplemented");
4422 if (NULL == exception) caml_invalid_argument("Curl.NotImplemented");
4425 caml_raise_with_string(*exception, thisOption->name);
4428 else
4430 caml_failwith("Invalid CURLMOPT Option");
4433 CAMLreturn(Val_unit);
4436 #ifdef __cplusplus
4438 #endif