xref: /PHP-5.4/ext/curl/interface.c (revision 0ea75af9)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 5                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2014 The PHP Group                                |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP license,      |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.php.net/license/3_01.txt                                  |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
15    | Author: Sterling Hughes <sterling@php.net>                           |
16    +----------------------------------------------------------------------+
17 */
18 
19 /* $Id$ */
20 
21 #define ZEND_INCLUDE_FULL_WINDOWS_HEADERS
22 
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 
27 #include "php.h"
28 
29 #if HAVE_CURL
30 
31 #include <stdio.h>
32 #include <string.h>
33 
34 #ifdef PHP_WIN32
35 #include <winsock2.h>
36 #include <sys/types.h>
37 #endif
38 
39 #include <curl/curl.h>
40 #include <curl/easy.h>
41 
42 /* As of curl 7.11.1 this is no longer defined inside curl.h */
43 #ifndef HttpPost
44 #define HttpPost curl_httppost
45 #endif
46 
47 /* {{{ cruft for thread safe SSL crypto locks */
48 #if defined(ZTS) && defined(HAVE_CURL_SSL)
49 # ifdef PHP_WIN32
50 #  define PHP_CURL_NEED_OPENSSL_TSL
51 #  include <openssl/crypto.h>
52 # else /* !PHP_WIN32 */
53 #  if defined(HAVE_CURL_OPENSSL)
54 #   if defined(HAVE_OPENSSL_CRYPTO_H)
55 #    define PHP_CURL_NEED_OPENSSL_TSL
56 #    include <openssl/crypto.h>
57 #   else
58 #    warning \
59 	"libcurl was compiled with OpenSSL support, but configure could not find " \
60 	"openssl/crypto.h; thus no SSL crypto locking callbacks will be set, which may " \
61 	"cause random crashes on SSL requests"
62 #   endif
63 #  elif defined(HAVE_CURL_GNUTLS)
64 #   if defined(HAVE_GCRYPT_H)
65 #    define PHP_CURL_NEED_GNUTLS_TSL
66 #    include <gcrypt.h>
67 #   else
68 #    warning \
69 	"libcurl was compiled with GnuTLS support, but configure could not find " \
70 	"gcrypt.h; thus no SSL crypto locking callbacks will be set, which may " \
71 	"cause random crashes on SSL requests"
72 #   endif
73 #  else
74 #   warning \
75 	"libcurl was compiled with SSL support, but configure could not determine which" \
76 	"library was used; thus no SSL crypto locking callbacks will be set, which may " \
77 	"cause random crashes on SSL requests"
78 #  endif /* HAVE_CURL_OPENSSL || HAVE_CURL_GNUTLS */
79 # endif /* PHP_WIN32 */
80 #endif /* ZTS && HAVE_CURL_SSL */
81 /* }}} */
82 
83 #define SMART_STR_PREALLOC 4096
84 
85 #include "ext/standard/php_smart_str.h"
86 #include "ext/standard/info.h"
87 #include "ext/standard/file.h"
88 #include "ext/standard/url.h"
89 #include "php_curl.h"
90 
91 int  le_curl;
92 int  le_curl_multi_handle;
93 
94 #ifdef PHP_CURL_NEED_OPENSSL_TSL /* {{{ */
95 static MUTEX_T *php_curl_openssl_tsl = NULL;
96 
php_curl_ssl_lock(int mode,int n,const char * file,int line)97 static void php_curl_ssl_lock(int mode, int n, const char * file, int line)
98 {
99 	if (mode & CRYPTO_LOCK) {
100 		tsrm_mutex_lock(php_curl_openssl_tsl[n]);
101 	} else {
102 		tsrm_mutex_unlock(php_curl_openssl_tsl[n]);
103 	}
104 }
105 
php_curl_ssl_id(void)106 static unsigned long php_curl_ssl_id(void)
107 {
108 	return (unsigned long) tsrm_thread_id();
109 }
110 #endif
111 /* }}} */
112 
113 #ifdef PHP_CURL_NEED_GNUTLS_TSL /* {{{ */
php_curl_ssl_mutex_create(void ** m)114 static int php_curl_ssl_mutex_create(void **m)
115 {
116 	if (*((MUTEX_T *) m) = tsrm_mutex_alloc()) {
117 		return SUCCESS;
118 	} else {
119 		return FAILURE;
120 	}
121 }
122 
php_curl_ssl_mutex_destroy(void ** m)123 static int php_curl_ssl_mutex_destroy(void **m)
124 {
125 	tsrm_mutex_free(*((MUTEX_T *) m));
126 	return SUCCESS;
127 }
128 
php_curl_ssl_mutex_lock(void ** m)129 static int php_curl_ssl_mutex_lock(void **m)
130 {
131 	return tsrm_mutex_lock(*((MUTEX_T *) m));
132 }
133 
php_curl_ssl_mutex_unlock(void ** m)134 static int php_curl_ssl_mutex_unlock(void **m)
135 {
136 	return tsrm_mutex_unlock(*((MUTEX_T *) m));
137 }
138 
139 static struct gcry_thread_cbs php_curl_gnutls_tsl = {
140 	GCRY_THREAD_OPTION_USER,
141 	NULL,
142 	php_curl_ssl_mutex_create,
143 	php_curl_ssl_mutex_destroy,
144 	php_curl_ssl_mutex_lock,
145 	php_curl_ssl_mutex_unlock
146 };
147 #endif
148 /* }}} */
149 
150 static void _php_curl_close_ex(php_curl *ch TSRMLS_DC);
151 static void _php_curl_close(zend_rsrc_list_entry *rsrc TSRMLS_DC);
152 
153 
154 #define SAVE_CURL_ERROR(__handle, __err) (__handle)->err.no = (int) __err;
155 
156 #define CAAL(s, v) add_assoc_long_ex(return_value, s, sizeof(s), (long) v);
157 #define CAAD(s, v) add_assoc_double_ex(return_value, s, sizeof(s), (double) v);
158 #define CAAS(s, v) add_assoc_string_ex(return_value, s, sizeof(s), (char *) (v ? v : ""), 1);
159 #define CAAZ(s, v) add_assoc_zval_ex(return_value, s, sizeof(s), (zval *) v);
160 
161 #if defined(PHP_WIN32) || defined(__GNUC__)
162 # define php_curl_ret(__ret) RETVAL_FALSE; return __ret;
163 #else
164 # define php_curl_ret(__ret) RETVAL_FALSE; return;
165 #endif
166 
php_curl_option_url(php_curl * ch,const char * url,const int len TSRMLS_DC)167 static int php_curl_option_url(php_curl *ch, const char *url, const int len TSRMLS_DC) /* {{{ */
168 {
169 	CURLcode error = CURLE_OK;
170 #if LIBCURL_VERSION_NUM < 0x071100
171 	char *copystr = NULL;
172 #endif
173 
174 	if (strlen(url) != len) {
175 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Curl option contains invalid characters (\\0)");
176 		return 0;
177 	}
178 
179 	/* Disable file:// if open_basedir are used */
180 	if (PG(open_basedir) && *PG(open_basedir)) {
181 #if LIBCURL_VERSION_NUM >= 0x071304
182 		error = curl_easy_setopt(ch->cp, CURLOPT_PROTOCOLS, CURLPROTO_ALL & ~CURLPROTO_FILE);
183 #else
184 		php_url *uri;
185 
186 		if (!(uri = php_url_parse_ex(url, len))) {
187 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid URL '%s'", url);
188 			return 0;
189 		}
190 
191 		if (uri->scheme && !strncasecmp("file", uri->scheme, sizeof("file"))) {
192 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Protocol 'file' disabled in cURL");
193 			php_url_free(uri);
194 			return 0;
195 		}
196 		php_url_free(uri);
197 #endif
198 	}
199 	/* Strings passed to libcurl as 'char *' arguments, are copied by the library... NOTE: before 7.17.0 strings were not copied. */
200 #if LIBCURL_VERSION_NUM >= 0x071100
201 	error = curl_easy_setopt(ch->cp, CURLOPT_URL, url);
202 #else
203 	copystr = estrndup(url, len);
204 	error = curl_easy_setopt(ch->cp, CURLOPT_URL, copystr);
205 	zend_llist_add_element(&ch->to_free->str, &copystr);
206 #endif
207 
208 	return (error == CURLE_OK ? 1 : 0);
209 }
210 /* }}} */
211 
_php_curl_verify_handlers(php_curl * ch,int reporterror TSRMLS_DC)212 int _php_curl_verify_handlers(php_curl *ch, int reporterror TSRMLS_DC) /* {{{ */
213 {
214 	php_stream *stream;
215 	if (!ch || !ch->handlers) {
216 		return 0;
217 	}
218 
219 	if (ch->handlers->std_err) {
220 		stream = (php_stream *) zend_fetch_resource(&ch->handlers->std_err TSRMLS_CC, -1, NULL, NULL, 2, php_file_le_stream(), php_file_le_pstream());
221 		if (stream == NULL) {
222 			if (reporterror) {
223 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "CURLOPT_STDERR resource has gone away, resetting to stderr");
224 			}
225 			zval_ptr_dtor(&ch->handlers->std_err);
226 			ch->handlers->std_err = NULL;
227 
228 			curl_easy_setopt(ch->cp, CURLOPT_STDERR, stderr);
229 		}
230 	}
231 	if (ch->handlers->read && ch->handlers->read->stream) {
232 		stream = (php_stream *) zend_fetch_resource(&ch->handlers->read->stream TSRMLS_CC, -1, NULL, NULL, 2, php_file_le_stream(), php_file_le_pstream());
233 		if (stream == NULL) {
234 			if (reporterror) {
235 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "CURLOPT_INFILE resource has gone away, resetting to default");
236 			}
237 			zval_ptr_dtor(&ch->handlers->read->stream);
238 			ch->handlers->read->fd = 0;
239 			ch->handlers->read->fp = 0;
240 			ch->handlers->read->stream = NULL;
241 
242 			curl_easy_setopt(ch->cp, CURLOPT_INFILE, (void *) ch);
243 		}
244 	}
245 	if (ch->handlers->write_header && ch->handlers->write_header->stream) {
246 		stream = (php_stream *) zend_fetch_resource(&ch->handlers->write_header->stream TSRMLS_CC, -1, NULL, NULL, 2, php_file_le_stream(), php_file_le_pstream());
247 		if (stream == NULL) {
248 			if (reporterror) {
249 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "CURLOPT_WRITEHEADER resource has gone away, resetting to default");
250 			}
251 			zval_ptr_dtor(&ch->handlers->write_header->stream);
252 			ch->handlers->write_header->fp = 0;
253 			ch->handlers->write_header->stream = NULL;
254 
255 			ch->handlers->write_header->method = PHP_CURL_IGNORE;
256 			curl_easy_setopt(ch->cp, CURLOPT_WRITEHEADER, (void *) ch);
257 		}
258 	}
259 	if (ch->handlers->write && ch->handlers->write->stream) {
260 		stream = (php_stream *) zend_fetch_resource(&ch->handlers->write->stream TSRMLS_CC, -1, NULL, NULL, 2, php_file_le_stream(), php_file_le_pstream());
261 		if (stream == NULL) {
262 			if (reporterror) {
263 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "CURLOPT_FILE resource has gone away, resetting to default");
264 			}
265 			zval_ptr_dtor(&ch->handlers->write->stream);
266 			ch->handlers->write->fp = 0;
267 			ch->handlers->write->stream = NULL;
268 
269 			ch->handlers->write->method = PHP_CURL_STDOUT;
270 			ch->handlers->write->type   = PHP_CURL_ASCII;
271 			curl_easy_setopt(ch->cp, CURLOPT_FILE, (void *) ch);
272 		}
273 	}
274 	return 1;
275 }
276 /* }}} */
277 
278 /* {{{ arginfo */
279 ZEND_BEGIN_ARG_INFO_EX(arginfo_curl_version, 0, 0, 0)
280 	ZEND_ARG_INFO(0, version)
281 ZEND_END_ARG_INFO()
282 
283 ZEND_BEGIN_ARG_INFO_EX(arginfo_curl_init, 0, 0, 0)
284 	ZEND_ARG_INFO(0, url)
285 ZEND_END_ARG_INFO()
286 
287 ZEND_BEGIN_ARG_INFO(arginfo_curl_copy_handle, 0)
288 	ZEND_ARG_INFO(0, ch)
289 ZEND_END_ARG_INFO()
290 
291 ZEND_BEGIN_ARG_INFO(arginfo_curl_setopt, 0)
292 	ZEND_ARG_INFO(0, ch)
293 	ZEND_ARG_INFO(0, option)
294 	ZEND_ARG_INFO(0, value)
295 ZEND_END_ARG_INFO()
296 
297 ZEND_BEGIN_ARG_INFO(arginfo_curl_setopt_array, 0)
298 	ZEND_ARG_INFO(0, ch)
299 	ZEND_ARG_ARRAY_INFO(0, options, 0)
300 ZEND_END_ARG_INFO()
301 
302 ZEND_BEGIN_ARG_INFO(arginfo_curl_exec, 0)
303 	ZEND_ARG_INFO(0, ch)
304 ZEND_END_ARG_INFO()
305 
306 ZEND_BEGIN_ARG_INFO_EX(arginfo_curl_getinfo, 0, 0, 1)
307 	ZEND_ARG_INFO(0, ch)
308 	ZEND_ARG_INFO(0, option)
309 ZEND_END_ARG_INFO()
310 
311 ZEND_BEGIN_ARG_INFO(arginfo_curl_error, 0)
312 	ZEND_ARG_INFO(0, ch)
313 ZEND_END_ARG_INFO()
314 
315 ZEND_BEGIN_ARG_INFO(arginfo_curl_errno, 0)
316 	ZEND_ARG_INFO(0, ch)
317 ZEND_END_ARG_INFO()
318 
319 ZEND_BEGIN_ARG_INFO(arginfo_curl_close, 0)
320 	ZEND_ARG_INFO(0, ch)
321 ZEND_END_ARG_INFO()
322 
323 ZEND_BEGIN_ARG_INFO(arginfo_curl_multi_init, 0)
324 ZEND_END_ARG_INFO()
325 
326 ZEND_BEGIN_ARG_INFO(arginfo_curl_multi_add_handle, 0)
327 	ZEND_ARG_INFO(0, mh)
328 	ZEND_ARG_INFO(0, ch)
329 ZEND_END_ARG_INFO()
330 
331 ZEND_BEGIN_ARG_INFO(arginfo_curl_multi_remove_handle, 0)
332 	ZEND_ARG_INFO(0, mh)
333 	ZEND_ARG_INFO(0, ch)
334 ZEND_END_ARG_INFO()
335 
336 ZEND_BEGIN_ARG_INFO_EX(arginfo_curl_multi_select, 0, 0, 1)
337 	ZEND_ARG_INFO(0, mh)
338 	ZEND_ARG_INFO(0, timeout)
339 ZEND_END_ARG_INFO()
340 
341 ZEND_BEGIN_ARG_INFO_EX(arginfo_curl_multi_exec, 0, 0, 1)
342 	ZEND_ARG_INFO(0, mh)
343 	ZEND_ARG_INFO(1, still_running)
344 ZEND_END_ARG_INFO()
345 
346 ZEND_BEGIN_ARG_INFO(arginfo_curl_multi_getcontent, 0)
347 	ZEND_ARG_INFO(0, ch)
348 ZEND_END_ARG_INFO()
349 
350 ZEND_BEGIN_ARG_INFO_EX(arginfo_curl_multi_info_read, 0, 0, 1)
351 	ZEND_ARG_INFO(0, mh)
352 	ZEND_ARG_INFO(1, msgs_in_queue)
353 ZEND_END_ARG_INFO()
354 
355 ZEND_BEGIN_ARG_INFO(arginfo_curl_multi_close, 0)
356 	ZEND_ARG_INFO(0, mh)
357 ZEND_END_ARG_INFO()
358 /* }}} */
359 
360 /* {{{ curl_functions[]
361  */
362 const zend_function_entry curl_functions[] = {
363 	PHP_FE(curl_init,                arginfo_curl_init)
364 	PHP_FE(curl_copy_handle,         arginfo_curl_copy_handle)
365 	PHP_FE(curl_version,             arginfo_curl_version)
366 	PHP_FE(curl_setopt,              arginfo_curl_setopt)
367 	PHP_FE(curl_setopt_array,        arginfo_curl_setopt_array)
368 	PHP_FE(curl_exec,                arginfo_curl_exec)
369 	PHP_FE(curl_getinfo,             arginfo_curl_getinfo)
370 	PHP_FE(curl_error,               arginfo_curl_error)
371 	PHP_FE(curl_errno,               arginfo_curl_errno)
372 	PHP_FE(curl_close,               arginfo_curl_close)
373 	PHP_FE(curl_multi_init,          arginfo_curl_multi_init)
374 	PHP_FE(curl_multi_add_handle,    arginfo_curl_multi_add_handle)
375 	PHP_FE(curl_multi_remove_handle, arginfo_curl_multi_remove_handle)
376 	PHP_FE(curl_multi_select,        arginfo_curl_multi_select)
377 	PHP_FE(curl_multi_exec,          arginfo_curl_multi_exec)
378 	PHP_FE(curl_multi_getcontent,    arginfo_curl_multi_getcontent)
379 	PHP_FE(curl_multi_info_read,     arginfo_curl_multi_info_read)
380 	PHP_FE(curl_multi_close,         arginfo_curl_multi_close)
381 	PHP_FE_END
382 };
383 /* }}} */
384 
385 /* {{{ curl_module_entry
386  */
387 zend_module_entry curl_module_entry = {
388 	STANDARD_MODULE_HEADER,
389 	"curl",
390 	curl_functions,
391 	PHP_MINIT(curl),
392 	PHP_MSHUTDOWN(curl),
393 	NULL,
394 	NULL,
395 	PHP_MINFO(curl),
396 	NO_VERSION_YET,
397 	STANDARD_MODULE_PROPERTIES
398 };
399 /* }}} */
400 
401 #ifdef COMPILE_DL_CURL
402 ZEND_GET_MODULE (curl)
403 #endif
404 
405 /* {{{ PHP_INI_BEGIN */
PHP_INI_BEGIN()406 PHP_INI_BEGIN()
407 	PHP_INI_ENTRY("curl.cainfo", "", PHP_INI_SYSTEM, NULL)
408 PHP_INI_END()
409 /* }}} */
410 
411 /* {{{ PHP_MINFO_FUNCTION
412  */
413 PHP_MINFO_FUNCTION(curl)
414 {
415 	curl_version_info_data *d;
416 	char **p;
417 	char str[1024];
418 	size_t n = 0;
419 
420 	d = curl_version_info(CURLVERSION_NOW);
421 	php_info_print_table_start();
422 	php_info_print_table_row(2, "cURL support",    "enabled");
423 	php_info_print_table_row(2, "cURL Information", d->version);
424 	sprintf(str, "%d", d->age);
425 	php_info_print_table_row(2, "Age", str);
426 
427 	/* To update on each new cURL release using src/main.c in cURL sources */
428 	if (d->features) {
429 		struct feat {
430 			const char *name;
431 			int bitmask;
432 		};
433 
434 		unsigned int i;
435 
436 		static const struct feat feats[] = {
437 #if LIBCURL_VERSION_NUM > 0x070a06 /* 7.10.7 */
438 			{"AsynchDNS", CURL_VERSION_ASYNCHDNS},
439 #endif
440 #if LIBCURL_VERSION_NUM > 0x070a05 /* 7.10.6 */
441 			{"Debug", CURL_VERSION_DEBUG},
442 			{"GSS-Negotiate", CURL_VERSION_GSSNEGOTIATE},
443 #endif
444 #if LIBCURL_VERSION_NUM > 0x070b02 /* 7.12.0 */
445 			{"IDN", CURL_VERSION_IDN},
446 #endif
447 #ifdef CURL_VERSION_IPV6
448 			{"IPv6", CURL_VERSION_IPV6},
449 #endif
450 #if LIBCURL_VERSION_NUM > 0x070b00 /* 7.11.1 */
451 			{"Largefile", CURL_VERSION_LARGEFILE},
452 #endif
453 #if LIBCURL_VERSION_NUM > 0x070a05 /* 7.10.6 */
454 			{"NTLM", CURL_VERSION_NTLM},
455 #endif
456 #if LIBCURL_VERSION_NUM > 0x070a07 /* 7.10.8 */
457 			{"SPNEGO", CURL_VERSION_SPNEGO},
458 #endif
459 #ifdef CURL_VERSION_SSL
460 			{"SSL",  CURL_VERSION_SSL},
461 #endif
462 #if LIBCURL_VERSION_NUM > 0x070d01 /* 7.13.2 */
463 			{"SSPI",  CURL_VERSION_SSPI},
464 #endif
465 #ifdef CURL_VERSION_KERBEROS4
466 			{"krb4", CURL_VERSION_KERBEROS4},
467 #endif
468 #ifdef CURL_VERSION_LIBZ
469 			{"libz", CURL_VERSION_LIBZ},
470 #endif
471 #if LIBCURL_VERSION_NUM > 0x070f03 /* 7.15.4 */
472 			{"CharConv", CURL_VERSION_CONV},
473 #endif
474 			{NULL, 0}
475 		};
476 
477 		php_info_print_table_row(1, "Features");
478 		for(i=0; i<sizeof(feats)/sizeof(feats[0]); i++) {
479 			if (feats[i].name) {
480 				php_info_print_table_row(2, feats[i].name, d->features & feats[i].bitmask ? "Yes" : "No");
481 			}
482 		}
483 	}
484 
485 	n = 0;
486 	p = (char **) d->protocols;
487 	while (*p != NULL) {
488 			n += sprintf(str + n, "%s%s", *p, *(p + 1) != NULL ? ", " : "");
489 			p++;
490 	}
491 	php_info_print_table_row(2, "Protocols", str);
492 
493 	php_info_print_table_row(2, "Host", d->host);
494 
495 	if (d->ssl_version) {
496 		php_info_print_table_row(2, "SSL Version", d->ssl_version);
497 	}
498 
499 	if (d->libz_version) {
500 		php_info_print_table_row(2, "ZLib Version", d->libz_version);
501 	}
502 
503 #if defined(CURLVERSION_SECOND) && CURLVERSION_NOW >= CURLVERSION_SECOND
504 	if (d->ares) {
505 		php_info_print_table_row(2, "ZLib Version", d->ares);
506 	}
507 #endif
508 
509 #if defined(CURLVERSION_THIRD) && CURLVERSION_NOW >= CURLVERSION_THIRD
510 	if (d->libidn) {
511 		php_info_print_table_row(2, "libIDN Version", d->libidn);
512 	}
513 #endif
514 
515 #if LIBCURL_VERSION_NUM >= 0x071300
516 
517 	if (d->iconv_ver_num) {
518 		php_info_print_table_row(2, "IconV Version", d->iconv_ver_num);
519 	}
520 
521 	if (d->libssh_version) {
522 		php_info_print_table_row(2, "libSSH Version", d->libssh_version);
523 	}
524 #endif
525 	php_info_print_table_end();
526 }
527 /* }}} */
528 
529 #define REGISTER_CURL_CONSTANT(__c) REGISTER_LONG_CONSTANT(#__c, __c, CONST_CS | CONST_PERSISTENT)
530 
531 /* {{{ PHP_MINIT_FUNCTION
532  */
PHP_MINIT_FUNCTION(curl)533 PHP_MINIT_FUNCTION(curl)
534 {
535 	le_curl = zend_register_list_destructors_ex(_php_curl_close, NULL, "curl", module_number);
536 	le_curl_multi_handle = zend_register_list_destructors_ex(_php_curl_multi_close, NULL, "curl_multi", module_number);
537 
538 	REGISTER_INI_ENTRIES();
539 
540 	/* See http://curl.haxx.se/lxr/source/docs/libcurl/symbols-in-versions
541 	   or curl src/docs/libcurl/symbols-in-versions for a (almost) complete list
542 	   of options and which version they were introduced */
543 
544 	/* Constants for curl_setopt() */
545 #if LIBCURL_VERSION_NUM > 0x070a07 /* CURLOPT_IPRESOLVE is available since curl 7.10.8 */
546 	REGISTER_CURL_CONSTANT(CURLOPT_IPRESOLVE);
547 	REGISTER_CURL_CONSTANT(CURL_IPRESOLVE_WHATEVER);
548 	REGISTER_CURL_CONSTANT(CURL_IPRESOLVE_V4);
549 	REGISTER_CURL_CONSTANT(CURL_IPRESOLVE_V6);
550 #endif
551 	REGISTER_CURL_CONSTANT(CURLOPT_DNS_USE_GLOBAL_CACHE);
552 	REGISTER_CURL_CONSTANT(CURLOPT_DNS_CACHE_TIMEOUT);
553 	REGISTER_CURL_CONSTANT(CURLOPT_PORT);
554 	REGISTER_CURL_CONSTANT(CURLOPT_FILE);
555 	REGISTER_CURL_CONSTANT(CURLOPT_READDATA);
556 	REGISTER_CURL_CONSTANT(CURLOPT_INFILE);
557 	REGISTER_CURL_CONSTANT(CURLOPT_INFILESIZE);
558 	REGISTER_CURL_CONSTANT(CURLOPT_URL);
559 	REGISTER_CURL_CONSTANT(CURLOPT_PROXY);
560 	REGISTER_CURL_CONSTANT(CURLOPT_VERBOSE);
561 	REGISTER_CURL_CONSTANT(CURLOPT_HEADER);
562 	REGISTER_CURL_CONSTANT(CURLOPT_HTTPHEADER);
563 	REGISTER_CURL_CONSTANT(CURLOPT_NOPROGRESS);
564 	REGISTER_CURL_CONSTANT(CURLOPT_PROGRESSFUNCTION);
565 	REGISTER_CURL_CONSTANT(CURLOPT_NOBODY);
566 	REGISTER_CURL_CONSTANT(CURLOPT_FAILONERROR);
567 	REGISTER_CURL_CONSTANT(CURLOPT_UPLOAD);
568 	REGISTER_CURL_CONSTANT(CURLOPT_POST);
569 	REGISTER_CURL_CONSTANT(CURLOPT_FTPLISTONLY);
570 	REGISTER_CURL_CONSTANT(CURLOPT_FTPAPPEND);
571 	REGISTER_CURL_CONSTANT(CURLOPT_NETRC);
572 	REGISTER_CURL_CONSTANT(CURLOPT_FOLLOWLOCATION);
573 #if CURLOPT_FTPASCII != 0
574 	REGISTER_CURL_CONSTANT(CURLOPT_FTPASCII);
575 #endif
576 	REGISTER_CURL_CONSTANT(CURLOPT_PUT);
577 #if CURLOPT_MUTE != 0
578 	REGISTER_CURL_CONSTANT(CURLOPT_MUTE);
579 #endif
580 	REGISTER_CURL_CONSTANT(CURLOPT_USERPWD);
581 	REGISTER_CURL_CONSTANT(CURLOPT_PROXYUSERPWD);
582 	REGISTER_CURL_CONSTANT(CURLOPT_RANGE);
583 	REGISTER_CURL_CONSTANT(CURLOPT_TIMEOUT);
584 #if LIBCURL_VERSION_NUM > 0x071002
585 	REGISTER_CURL_CONSTANT(CURLOPT_TIMEOUT_MS);
586 #endif
587 	REGISTER_CURL_CONSTANT(CURLOPT_POSTFIELDS);
588 	REGISTER_CURL_CONSTANT(CURLOPT_REFERER);
589 	REGISTER_CURL_CONSTANT(CURLOPT_USERAGENT);
590 	REGISTER_CURL_CONSTANT(CURLOPT_FTPPORT);
591 	REGISTER_CURL_CONSTANT(CURLOPT_FTP_USE_EPSV);
592 	REGISTER_CURL_CONSTANT(CURLOPT_LOW_SPEED_LIMIT);
593 	REGISTER_CURL_CONSTANT(CURLOPT_LOW_SPEED_TIME);
594 	REGISTER_CURL_CONSTANT(CURLOPT_RESUME_FROM);
595 	REGISTER_CURL_CONSTANT(CURLOPT_COOKIE);
596 	REGISTER_CURL_CONSTANT(CURLOPT_COOKIESESSION);
597 	REGISTER_CURL_CONSTANT(CURLOPT_AUTOREFERER);
598 	REGISTER_CURL_CONSTANT(CURLOPT_SSLCERT);
599 	REGISTER_CURL_CONSTANT(CURLOPT_SSLCERTPASSWD);
600 	REGISTER_CURL_CONSTANT(CURLOPT_WRITEHEADER);
601 	REGISTER_CURL_CONSTANT(CURLOPT_SSL_VERIFYHOST);
602 	REGISTER_CURL_CONSTANT(CURLOPT_COOKIEFILE);
603 	REGISTER_CURL_CONSTANT(CURLOPT_SSLVERSION);
604 	REGISTER_CURL_CONSTANT(CURLOPT_TIMECONDITION);
605 	REGISTER_CURL_CONSTANT(CURLOPT_TIMEVALUE);
606 	REGISTER_CURL_CONSTANT(CURLOPT_CUSTOMREQUEST);
607 	REGISTER_CURL_CONSTANT(CURLOPT_STDERR);
608 	REGISTER_CURL_CONSTANT(CURLOPT_TRANSFERTEXT);
609 	REGISTER_CURL_CONSTANT(CURLOPT_RETURNTRANSFER);
610 	REGISTER_CURL_CONSTANT(CURLOPT_QUOTE);
611 	REGISTER_CURL_CONSTANT(CURLOPT_POSTQUOTE);
612 	REGISTER_CURL_CONSTANT(CURLOPT_INTERFACE);
613 	REGISTER_CURL_CONSTANT(CURLOPT_KRB4LEVEL);
614 	REGISTER_CURL_CONSTANT(CURLOPT_HTTPPROXYTUNNEL);
615 	REGISTER_CURL_CONSTANT(CURLOPT_FILETIME);
616 	REGISTER_CURL_CONSTANT(CURLOPT_WRITEFUNCTION);
617 	REGISTER_CURL_CONSTANT(CURLOPT_READFUNCTION);
618 #if CURLOPT_PASSWDFUNCTION != 0
619 	REGISTER_CURL_CONSTANT(CURLOPT_PASSWDFUNCTION);
620 #endif
621 	REGISTER_CURL_CONSTANT(CURLOPT_HEADERFUNCTION);
622 	REGISTER_CURL_CONSTANT(CURLOPT_MAXREDIRS);
623 	REGISTER_CURL_CONSTANT(CURLOPT_MAXCONNECTS);
624 	REGISTER_CURL_CONSTANT(CURLOPT_CLOSEPOLICY);
625 	REGISTER_CURL_CONSTANT(CURLOPT_FRESH_CONNECT);
626 	REGISTER_CURL_CONSTANT(CURLOPT_FORBID_REUSE);
627 	REGISTER_CURL_CONSTANT(CURLOPT_RANDOM_FILE);
628 	REGISTER_CURL_CONSTANT(CURLOPT_EGDSOCKET);
629 	REGISTER_CURL_CONSTANT(CURLOPT_CONNECTTIMEOUT);
630 #if LIBCURL_VERSION_NUM > 0x071002
631 	REGISTER_CURL_CONSTANT(CURLOPT_CONNECTTIMEOUT_MS);
632 #endif
633 	REGISTER_CURL_CONSTANT(CURLOPT_SSL_VERIFYPEER);
634 	REGISTER_CURL_CONSTANT(CURLOPT_CAINFO);
635 	REGISTER_CURL_CONSTANT(CURLOPT_CAPATH);
636 	REGISTER_CURL_CONSTANT(CURLOPT_COOKIEJAR);
637 	REGISTER_CURL_CONSTANT(CURLOPT_SSL_CIPHER_LIST);
638 	REGISTER_CURL_CONSTANT(CURLOPT_BINARYTRANSFER);
639 	REGISTER_CURL_CONSTANT(CURLOPT_NOSIGNAL);
640 	REGISTER_CURL_CONSTANT(CURLOPT_PROXYTYPE);
641 	REGISTER_CURL_CONSTANT(CURLOPT_BUFFERSIZE);
642 	REGISTER_CURL_CONSTANT(CURLOPT_HTTPGET);
643 	REGISTER_CURL_CONSTANT(CURLOPT_HTTP_VERSION);
644 	REGISTER_CURL_CONSTANT(CURLOPT_SSLKEY);
645 	REGISTER_CURL_CONSTANT(CURLOPT_SSLKEYTYPE);
646 	REGISTER_CURL_CONSTANT(CURLOPT_SSLKEYPASSWD);
647 	REGISTER_CURL_CONSTANT(CURLOPT_SSLENGINE);
648 	REGISTER_CURL_CONSTANT(CURLOPT_SSLENGINE_DEFAULT);
649 	REGISTER_CURL_CONSTANT(CURLOPT_SSLCERTTYPE);
650 	REGISTER_CURL_CONSTANT(CURLOPT_CRLF);
651 	REGISTER_CURL_CONSTANT(CURLOPT_ENCODING);
652 	REGISTER_CURL_CONSTANT(CURLOPT_PROXYPORT);
653 	REGISTER_CURL_CONSTANT(CURLOPT_UNRESTRICTED_AUTH);
654 	REGISTER_CURL_CONSTANT(CURLOPT_FTP_USE_EPRT);
655 #if LIBCURL_VERSION_NUM > 0x070b01 /* CURLOPT_TCP_NODELAY is available since curl 7.11.2 */
656 	REGISTER_CURL_CONSTANT(CURLOPT_TCP_NODELAY);
657 #endif
658 	REGISTER_CURL_CONSTANT(CURLOPT_HTTP200ALIASES);
659 	REGISTER_CURL_CONSTANT(CURL_TIMECOND_IFMODSINCE);
660 	REGISTER_CURL_CONSTANT(CURL_TIMECOND_IFUNMODSINCE);
661 	REGISTER_CURL_CONSTANT(CURL_TIMECOND_LASTMOD);
662 
663 #if LIBCURL_VERSION_NUM > 0x070f04 /* CURLOPT_MAX_RECV_SPEED_LARGE & CURLOPT_MAX_SEND_SPEED_LARGE  are available since curl 7.15.5 */
664 	REGISTER_CURL_CONSTANT(CURLOPT_MAX_RECV_SPEED_LARGE);
665 	REGISTER_CURL_CONSTANT(CURLOPT_MAX_SEND_SPEED_LARGE);
666 #endif
667 
668 #if LIBCURL_VERSION_NUM > 0x070a05 /* CURLOPT_HTTPAUTH is available since curl 7.10.6 */
669 	REGISTER_CURL_CONSTANT(CURLOPT_HTTPAUTH);
670 	/* http authentication options */
671 	REGISTER_CURL_CONSTANT(CURLAUTH_BASIC);
672 	REGISTER_CURL_CONSTANT(CURLAUTH_DIGEST);
673 	REGISTER_CURL_CONSTANT(CURLAUTH_GSSNEGOTIATE);
674 	REGISTER_CURL_CONSTANT(CURLAUTH_NTLM);
675 	REGISTER_CURL_CONSTANT(CURLAUTH_ANY);
676 	REGISTER_CURL_CONSTANT(CURLAUTH_ANYSAFE);
677 #endif
678 
679 #if LIBCURL_VERSION_NUM > 0x070a06 /* CURLOPT_PROXYAUTH & CURLOPT_FTP_CREATE_MISSING_DIRS are available since curl 7.10.7 */
680 	REGISTER_CURL_CONSTANT(CURLOPT_PROXYAUTH);
681 	REGISTER_CURL_CONSTANT(CURLOPT_FTP_CREATE_MISSING_DIRS);
682 #endif
683 
684 	REGISTER_CURL_CONSTANT(CURLOPT_PRIVATE);
685 
686 	/* Constants effecting the way CURLOPT_CLOSEPOLICY works */
687 	REGISTER_CURL_CONSTANT(CURLCLOSEPOLICY_LEAST_RECENTLY_USED);
688 	REGISTER_CURL_CONSTANT(CURLCLOSEPOLICY_LEAST_TRAFFIC);
689 	REGISTER_CURL_CONSTANT(CURLCLOSEPOLICY_SLOWEST);
690 	REGISTER_CURL_CONSTANT(CURLCLOSEPOLICY_CALLBACK);
691 	REGISTER_CURL_CONSTANT(CURLCLOSEPOLICY_OLDEST);
692 
693 	/* Info constants */
694 	REGISTER_CURL_CONSTANT(CURLINFO_EFFECTIVE_URL);
695 	REGISTER_CURL_CONSTANT(CURLINFO_HTTP_CODE);
696 	REGISTER_CURL_CONSTANT(CURLINFO_HEADER_SIZE);
697 	REGISTER_CURL_CONSTANT(CURLINFO_REQUEST_SIZE);
698 	REGISTER_CURL_CONSTANT(CURLINFO_TOTAL_TIME);
699 	REGISTER_CURL_CONSTANT(CURLINFO_NAMELOOKUP_TIME);
700 	REGISTER_CURL_CONSTANT(CURLINFO_CONNECT_TIME);
701 	REGISTER_CURL_CONSTANT(CURLINFO_PRETRANSFER_TIME);
702 	REGISTER_CURL_CONSTANT(CURLINFO_SIZE_UPLOAD);
703 	REGISTER_CURL_CONSTANT(CURLINFO_SIZE_DOWNLOAD);
704 	REGISTER_CURL_CONSTANT(CURLINFO_SPEED_DOWNLOAD);
705 	REGISTER_CURL_CONSTANT(CURLINFO_SPEED_UPLOAD);
706 	REGISTER_CURL_CONSTANT(CURLINFO_FILETIME);
707 	REGISTER_CURL_CONSTANT(CURLINFO_SSL_VERIFYRESULT);
708 	REGISTER_CURL_CONSTANT(CURLINFO_CONTENT_LENGTH_DOWNLOAD);
709 	REGISTER_CURL_CONSTANT(CURLINFO_CONTENT_LENGTH_UPLOAD);
710 	REGISTER_CURL_CONSTANT(CURLINFO_STARTTRANSFER_TIME);
711 	REGISTER_CURL_CONSTANT(CURLINFO_CONTENT_TYPE);
712 	REGISTER_CURL_CONSTANT(CURLINFO_REDIRECT_TIME);
713 	REGISTER_CURL_CONSTANT(CURLINFO_REDIRECT_COUNT);
714 	REGISTER_CURL_CONSTANT(CURLINFO_HEADER_OUT);
715 	REGISTER_CURL_CONSTANT(CURLINFO_PRIVATE);
716 #if LIBCURL_VERSION_NUM >  0x071301
717 	REGISTER_CURL_CONSTANT(CURLINFO_CERTINFO);
718 #endif
719 #if LIBCURL_VERSION_NUM >= 0x071202
720     REGISTER_CURL_CONSTANT(CURLINFO_REDIRECT_URL);
721 #endif
722 #if LIBCURL_VERSION_NUM >= 0x071300 /* 7.19.0 */
723 	REGISTER_CURL_CONSTANT(CURLINFO_PRIMARY_IP);
724 #endif
725 #if LIBCURL_VERSION_NUM >= 0x071500 /* 7.21.0 */
726 	REGISTER_CURL_CONSTANT(CURLINFO_PRIMARY_PORT);
727 	REGISTER_CURL_CONSTANT(CURLINFO_LOCAL_IP);
728 	REGISTER_CURL_CONSTANT(CURLINFO_LOCAL_PORT);
729 #endif
730 
731 
732 	/* cURL protocol constants (curl_version) */
733 	REGISTER_CURL_CONSTANT(CURL_VERSION_IPV6);
734 	REGISTER_CURL_CONSTANT(CURL_VERSION_KERBEROS4);
735 	REGISTER_CURL_CONSTANT(CURL_VERSION_SSL);
736 	REGISTER_CURL_CONSTANT(CURL_VERSION_LIBZ);
737 
738 	/* version constants */
739 	REGISTER_CURL_CONSTANT(CURLVERSION_NOW);
740 
741 	/* Error Constants */
742 	REGISTER_CURL_CONSTANT(CURLE_OK);
743 	REGISTER_CURL_CONSTANT(CURLE_UNSUPPORTED_PROTOCOL);
744 	REGISTER_CURL_CONSTANT(CURLE_FAILED_INIT);
745 	REGISTER_CURL_CONSTANT(CURLE_URL_MALFORMAT);
746 	REGISTER_CURL_CONSTANT(CURLE_URL_MALFORMAT_USER);
747 	REGISTER_CURL_CONSTANT(CURLE_COULDNT_RESOLVE_PROXY);
748 	REGISTER_CURL_CONSTANT(CURLE_COULDNT_RESOLVE_HOST);
749 	REGISTER_CURL_CONSTANT(CURLE_COULDNT_CONNECT);
750 	REGISTER_CURL_CONSTANT(CURLE_FTP_WEIRD_SERVER_REPLY);
751 	REGISTER_CURL_CONSTANT(CURLE_FTP_ACCESS_DENIED);
752 	REGISTER_CURL_CONSTANT(CURLE_FTP_USER_PASSWORD_INCORRECT);
753 	REGISTER_CURL_CONSTANT(CURLE_FTP_WEIRD_PASS_REPLY);
754 	REGISTER_CURL_CONSTANT(CURLE_FTP_WEIRD_USER_REPLY);
755 	REGISTER_CURL_CONSTANT(CURLE_FTP_WEIRD_PASV_REPLY);
756 	REGISTER_CURL_CONSTANT(CURLE_FTP_WEIRD_227_FORMAT);
757 	REGISTER_CURL_CONSTANT(CURLE_FTP_CANT_GET_HOST);
758 	REGISTER_CURL_CONSTANT(CURLE_FTP_CANT_RECONNECT);
759 	REGISTER_CURL_CONSTANT(CURLE_FTP_COULDNT_SET_BINARY);
760 	REGISTER_CURL_CONSTANT(CURLE_PARTIAL_FILE);
761 	REGISTER_CURL_CONSTANT(CURLE_FTP_COULDNT_RETR_FILE);
762 	REGISTER_CURL_CONSTANT(CURLE_FTP_WRITE_ERROR);
763 	REGISTER_CURL_CONSTANT(CURLE_FTP_QUOTE_ERROR);
764 	REGISTER_CURL_CONSTANT(CURLE_HTTP_NOT_FOUND);
765 	REGISTER_CURL_CONSTANT(CURLE_WRITE_ERROR);
766 	REGISTER_CURL_CONSTANT(CURLE_MALFORMAT_USER);
767 	REGISTER_CURL_CONSTANT(CURLE_FTP_COULDNT_STOR_FILE);
768 	REGISTER_CURL_CONSTANT(CURLE_READ_ERROR);
769 	REGISTER_CURL_CONSTANT(CURLE_OUT_OF_MEMORY);
770 	REGISTER_CURL_CONSTANT(CURLE_OPERATION_TIMEOUTED);
771 	REGISTER_CURL_CONSTANT(CURLE_FTP_COULDNT_SET_ASCII);
772 	REGISTER_CURL_CONSTANT(CURLE_FTP_PORT_FAILED);
773 	REGISTER_CURL_CONSTANT(CURLE_FTP_COULDNT_USE_REST);
774 	REGISTER_CURL_CONSTANT(CURLE_FTP_COULDNT_GET_SIZE);
775 	REGISTER_CURL_CONSTANT(CURLE_HTTP_RANGE_ERROR);
776 	REGISTER_CURL_CONSTANT(CURLE_HTTP_POST_ERROR);
777 	REGISTER_CURL_CONSTANT(CURLE_SSL_CONNECT_ERROR);
778 	REGISTER_CURL_CONSTANT(CURLE_FTP_BAD_DOWNLOAD_RESUME);
779 	REGISTER_CURL_CONSTANT(CURLE_FILE_COULDNT_READ_FILE);
780 	REGISTER_CURL_CONSTANT(CURLE_LDAP_CANNOT_BIND);
781 	REGISTER_CURL_CONSTANT(CURLE_LDAP_SEARCH_FAILED);
782 	REGISTER_CURL_CONSTANT(CURLE_LIBRARY_NOT_FOUND);
783 	REGISTER_CURL_CONSTANT(CURLE_FUNCTION_NOT_FOUND);
784 	REGISTER_CURL_CONSTANT(CURLE_ABORTED_BY_CALLBACK);
785 	REGISTER_CURL_CONSTANT(CURLE_BAD_FUNCTION_ARGUMENT);
786 	REGISTER_CURL_CONSTANT(CURLE_BAD_CALLING_ORDER);
787 	REGISTER_CURL_CONSTANT(CURLE_HTTP_PORT_FAILED);
788 	REGISTER_CURL_CONSTANT(CURLE_BAD_PASSWORD_ENTERED);
789 	REGISTER_CURL_CONSTANT(CURLE_TOO_MANY_REDIRECTS);
790 	REGISTER_CURL_CONSTANT(CURLE_UNKNOWN_TELNET_OPTION);
791 	REGISTER_CURL_CONSTANT(CURLE_TELNET_OPTION_SYNTAX);
792 	REGISTER_CURL_CONSTANT(CURLE_OBSOLETE);
793 	REGISTER_CURL_CONSTANT(CURLE_SSL_PEER_CERTIFICATE);
794 	REGISTER_CURL_CONSTANT(CURLE_GOT_NOTHING);
795 	REGISTER_CURL_CONSTANT(CURLE_SSL_ENGINE_NOTFOUND);
796 	REGISTER_CURL_CONSTANT(CURLE_SSL_ENGINE_SETFAILED);
797 	REGISTER_CURL_CONSTANT(CURLE_SEND_ERROR);
798 	REGISTER_CURL_CONSTANT(CURLE_RECV_ERROR);
799 	REGISTER_CURL_CONSTANT(CURLE_SHARE_IN_USE);
800 	REGISTER_CURL_CONSTANT(CURLE_SSL_CERTPROBLEM);
801 	REGISTER_CURL_CONSTANT(CURLE_SSL_CIPHER);
802 	REGISTER_CURL_CONSTANT(CURLE_SSL_CACERT);
803 	REGISTER_CURL_CONSTANT(CURLE_BAD_CONTENT_ENCODING);
804 #if LIBCURL_VERSION_NUM >= 0x070a08
805 	REGISTER_CURL_CONSTANT(CURLE_LDAP_INVALID_URL);
806 	REGISTER_CURL_CONSTANT(CURLE_FILESIZE_EXCEEDED);
807 #endif
808 #if LIBCURL_VERSION_NUM >= 0x070b00
809 	REGISTER_CURL_CONSTANT(CURLE_FTP_SSL_FAILED);
810 #endif
811 	REGISTER_CURL_CONSTANT(CURLPROXY_HTTP);
812 	REGISTER_CURL_CONSTANT(CURLPROXY_SOCKS4);
813 	REGISTER_CURL_CONSTANT(CURLPROXY_SOCKS5);
814 
815 	REGISTER_CURL_CONSTANT(CURL_NETRC_OPTIONAL);
816 	REGISTER_CURL_CONSTANT(CURL_NETRC_IGNORED);
817 	REGISTER_CURL_CONSTANT(CURL_NETRC_REQUIRED);
818 
819 	REGISTER_CURL_CONSTANT(CURL_HTTP_VERSION_NONE);
820 	REGISTER_CURL_CONSTANT(CURL_HTTP_VERSION_1_0);
821 	REGISTER_CURL_CONSTANT(CURL_HTTP_VERSION_1_1);
822 
823 	REGISTER_CURL_CONSTANT(CURLM_CALL_MULTI_PERFORM);
824 	REGISTER_CURL_CONSTANT(CURLM_OK);
825 	REGISTER_CURL_CONSTANT(CURLM_BAD_HANDLE);
826 	REGISTER_CURL_CONSTANT(CURLM_BAD_EASY_HANDLE);
827 	REGISTER_CURL_CONSTANT(CURLM_OUT_OF_MEMORY);
828 	REGISTER_CURL_CONSTANT(CURLM_INTERNAL_ERROR);
829 
830 	REGISTER_CURL_CONSTANT(CURLMSG_DONE);
831 
832 #if LIBCURL_VERSION_NUM >= 0x070c02
833 	REGISTER_CURL_CONSTANT(CURLOPT_FTPSSLAUTH);
834 	REGISTER_CURL_CONSTANT(CURLFTPAUTH_DEFAULT);
835 	REGISTER_CURL_CONSTANT(CURLFTPAUTH_SSL);
836 	REGISTER_CURL_CONSTANT(CURLFTPAUTH_TLS);
837 #endif
838 
839 #if LIBCURL_VERSION_NUM >  0x070b00
840 	REGISTER_CURL_CONSTANT(CURLOPT_FTP_SSL);
841 	REGISTER_CURL_CONSTANT(CURLFTPSSL_NONE);
842 	REGISTER_CURL_CONSTANT(CURLFTPSSL_TRY);
843 	REGISTER_CURL_CONSTANT(CURLFTPSSL_CONTROL);
844 	REGISTER_CURL_CONSTANT(CURLFTPSSL_ALL);
845 #endif
846 
847 #if LIBCURL_VERSION_NUM > 0x071301
848 	REGISTER_CURL_CONSTANT(CURLOPT_CERTINFO);
849 	REGISTER_CURL_CONSTANT(CURLOPT_POSTREDIR);
850 #endif
851 
852 /* SSH support works in 7.19.0+ using libssh2 */
853 #if LIBCURL_VERSION_NUM >= 0x071300
854 	REGISTER_CURL_CONSTANT(CURLSSH_AUTH_NONE);
855 	REGISTER_CURL_CONSTANT(CURLSSH_AUTH_PUBLICKEY);
856 	REGISTER_CURL_CONSTANT(CURLSSH_AUTH_PASSWORD);
857 	REGISTER_CURL_CONSTANT(CURLSSH_AUTH_HOST);
858 	REGISTER_CURL_CONSTANT(CURLSSH_AUTH_KEYBOARD);
859 	REGISTER_CURL_CONSTANT(CURLSSH_AUTH_DEFAULT);
860 	REGISTER_CURL_CONSTANT(CURLOPT_SSH_AUTH_TYPES);
861 	REGISTER_CURL_CONSTANT(CURLOPT_KEYPASSWD);
862 	REGISTER_CURL_CONSTANT(CURLOPT_SSH_PUBLIC_KEYFILE);
863 	REGISTER_CURL_CONSTANT(CURLOPT_SSH_PRIVATE_KEYFILE);
864 	REGISTER_CURL_CONSTANT(CURLOPT_SSH_HOST_PUBLIC_KEY_MD5);
865 	REGISTER_CURL_CONSTANT(CURLE_SSH);
866 #endif
867 
868 #if LIBCURL_VERSION_NUM >= 0x071304
869 	REGISTER_CURL_CONSTANT(CURLOPT_REDIR_PROTOCOLS);
870 	REGISTER_CURL_CONSTANT(CURLOPT_PROTOCOLS);
871 	REGISTER_CURL_CONSTANT(CURLPROTO_HTTP);
872 	REGISTER_CURL_CONSTANT(CURLPROTO_HTTPS);
873 	REGISTER_CURL_CONSTANT(CURLPROTO_FTP);
874 	REGISTER_CURL_CONSTANT(CURLPROTO_FTPS);
875 	REGISTER_CURL_CONSTANT(CURLPROTO_SCP);
876 	REGISTER_CURL_CONSTANT(CURLPROTO_SFTP);
877 	REGISTER_CURL_CONSTANT(CURLPROTO_TELNET);
878 	REGISTER_CURL_CONSTANT(CURLPROTO_LDAP);
879 	REGISTER_CURL_CONSTANT(CURLPROTO_LDAPS);
880 	REGISTER_CURL_CONSTANT(CURLPROTO_DICT);
881 	REGISTER_CURL_CONSTANT(CURLPROTO_FILE);
882 	REGISTER_CURL_CONSTANT(CURLPROTO_TFTP);
883 	REGISTER_CURL_CONSTANT(CURLPROTO_ALL);
884 #endif
885 
886 #if LIBCURL_VERSION_NUM >= 0x070f01
887 	REGISTER_CURL_CONSTANT(CURLOPT_FTP_FILEMETHOD);
888 	REGISTER_CURL_CONSTANT(CURLOPT_FTP_SKIP_PASV_IP);
889 #endif
890 
891 #if LIBCURL_VERSION_NUM >= 0x071001
892 	REGISTER_CURL_CONSTANT(CURLFTPMETHOD_MULTICWD);
893 	REGISTER_CURL_CONSTANT(CURLFTPMETHOD_NOCWD);
894 	REGISTER_CURL_CONSTANT(CURLFTPMETHOD_SINGLECWD);
895 #endif
896 
897 #ifdef PHP_CURL_NEED_OPENSSL_TSL
898 	if (!CRYPTO_get_id_callback()) {
899 		int i, c = CRYPTO_num_locks();
900 
901 		php_curl_openssl_tsl = malloc(c * sizeof(MUTEX_T));
902 		if (!php_curl_openssl_tsl) {
903 			return FAILURE;
904 		}
905 
906 		for (i = 0; i < c; ++i) {
907 			php_curl_openssl_tsl[i] = tsrm_mutex_alloc();
908 		}
909 
910 		CRYPTO_set_id_callback(php_curl_ssl_id);
911 		CRYPTO_set_locking_callback(php_curl_ssl_lock);
912 	}
913 #endif
914 #ifdef PHP_CURL_NEED_GNUTLS_TSL
915 	gcry_control(GCRYCTL_SET_THREAD_CBS, &php_curl_gnutls_tsl);
916 #endif
917 
918 	if (curl_global_init(CURL_GLOBAL_SSL) != CURLE_OK) {
919 		return FAILURE;
920 	}
921 
922 #ifdef PHP_CURL_URL_WRAPPERS
923 # if HAVE_CURL_VERSION_INFO
924 	{
925 		curl_version_info_data *info = curl_version_info(CURLVERSION_NOW);
926 		char **p = (char **)info->protocols;
927 
928 		while (*p != NULL) {
929 			/* Do not enable cURL "file" protocol and make sure cURL is always used when --with-curlwrappers is enabled */
930 			if (strncasecmp(*p, "file", sizeof("file")-1) != 0) {
931 				php_unregister_url_stream_wrapper(*p TSRMLS_CC);
932 				php_register_url_stream_wrapper(*p, &php_curl_wrapper TSRMLS_CC);
933 			}
934 			(void) *p++;
935 		}
936 	}
937 # else
938 	php_unregister_url_stream_wrapper("http");
939 	php_register_url_stream_wrapper("http", &php_curl_wrapper TSRMLS_CC);
940 	php_unregister_url_stream_wrapper("https");
941 	php_register_url_stream_wrapper("https", &php_curl_wrapper TSRMLS_CC);
942 	php_unregister_url_stream_wrapper("ftp");
943 	php_register_url_stream_wrapper("ftp", &php_curl_wrapper TSRMLS_CC);
944 	php_unregister_url_stream_wrapper("ftps");
945 	php_register_url_stream_wrapper("ftps", &php_curl_wrapper TSRMLS_CC);
946 	php_unregister_url_stream_wrapper("ldap");
947 	php_register_url_stream_wrapper("ldap", &php_curl_wrapper TSRMLS_CC);
948 # endif
949 #endif
950 
951 	return SUCCESS;
952 }
953 /* }}} */
954 
955 /* {{{ PHP_MSHUTDOWN_FUNCTION
956  */
PHP_MSHUTDOWN_FUNCTION(curl)957 PHP_MSHUTDOWN_FUNCTION(curl)
958 {
959 #ifdef PHP_CURL_URL_WRAPPERS
960 	php_unregister_url_stream_wrapper("http" TSRMLS_CC);
961 	php_unregister_url_stream_wrapper("https" TSRMLS_CC);
962 	php_unregister_url_stream_wrapper("ftp" TSRMLS_CC);
963 	php_unregister_url_stream_wrapper("ldap" TSRMLS_CC);
964 #endif
965 	curl_global_cleanup();
966 #ifdef PHP_CURL_NEED_OPENSSL_TSL
967 	if (php_curl_openssl_tsl) {
968 		int i, c = CRYPTO_num_locks();
969 
970 		CRYPTO_set_id_callback(NULL);
971 		CRYPTO_set_locking_callback(NULL);
972 
973 		for (i = 0; i < c; ++i) {
974 			tsrm_mutex_free(php_curl_openssl_tsl[i]);
975 		}
976 
977 		free(php_curl_openssl_tsl);
978 		php_curl_openssl_tsl = NULL;
979 	}
980 #endif
981 	UNREGISTER_INI_ENTRIES();
982 	return SUCCESS;
983 }
984 /* }}} */
985 
986 /* {{{ curl_write_nothing
987  * Used as a work around. See _php_curl_close_ex
988  */
curl_write_nothing(char * data,size_t size,size_t nmemb,void * ctx)989 static size_t curl_write_nothing(char *data, size_t size, size_t nmemb, void *ctx)
990 {
991 	return size * nmemb;
992 }
993 /* }}} */
994 
995 /* {{{ curl_write
996  */
curl_write(char * data,size_t size,size_t nmemb,void * ctx)997 static size_t curl_write(char *data, size_t size, size_t nmemb, void *ctx)
998 {
999 	php_curl       *ch     = (php_curl *) ctx;
1000 	php_curl_write *t      = ch->handlers->write;
1001 	size_t          length = size * nmemb;
1002 	TSRMLS_FETCH_FROM_CTX(ch->thread_ctx);
1003 
1004 #if PHP_CURL_DEBUG
1005 	fprintf(stderr, "curl_write() called\n");
1006 	fprintf(stderr, "data = %s, size = %d, nmemb = %d, ctx = %x\n", data, size, nmemb, ctx);
1007 #endif
1008 
1009 	switch (t->method) {
1010 		case PHP_CURL_STDOUT:
1011 			PHPWRITE(data, length);
1012 			break;
1013 		case PHP_CURL_FILE:
1014 			return fwrite(data, size, nmemb, t->fp);
1015 		case PHP_CURL_RETURN:
1016 			if (length > 0) {
1017 				smart_str_appendl(&t->buf, data, (int) length);
1018 			}
1019 			break;
1020 		case PHP_CURL_USER: {
1021 			zval **argv[2];
1022 			zval *retval_ptr = NULL;
1023 			zval *handle = NULL;
1024 			zval *zdata = NULL;
1025 			int   error;
1026 			zend_fcall_info fci;
1027 
1028 			MAKE_STD_ZVAL(handle);
1029 			ZVAL_RESOURCE(handle, ch->id);
1030 			zend_list_addref(ch->id);
1031 			argv[0] = &handle;
1032 
1033 			MAKE_STD_ZVAL(zdata);
1034 			ZVAL_STRINGL(zdata, data, length, 1);
1035 			argv[1] = &zdata;
1036 
1037 			fci.size = sizeof(fci);
1038 			fci.function_table = EG(function_table);
1039 			fci.object_ptr = NULL;
1040 			fci.function_name = t->func_name;
1041 			fci.retval_ptr_ptr = &retval_ptr;
1042 			fci.param_count = 2;
1043 			fci.params = argv;
1044 			fci.no_separation = 0;
1045 			fci.symbol_table = NULL;
1046 
1047 			ch->in_callback = 1;
1048 			error = zend_call_function(&fci, &t->fci_cache TSRMLS_CC);
1049 			ch->in_callback = 0;
1050 			if (error == FAILURE) {
1051 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not call the CURLOPT_WRITEFUNCTION");
1052 				length = -1;
1053 			} else if (retval_ptr) {
1054 				_php_curl_verify_handlers(ch, 1 TSRMLS_CC);
1055 				if (Z_TYPE_P(retval_ptr) != IS_LONG) {
1056 					convert_to_long_ex(&retval_ptr);
1057 				}
1058 				length = Z_LVAL_P(retval_ptr);
1059 				zval_ptr_dtor(&retval_ptr);
1060 			}
1061 
1062 			zval_ptr_dtor(argv[0]);
1063 			zval_ptr_dtor(argv[1]);
1064 			break;
1065 		}
1066 	}
1067 
1068 	return length;
1069 }
1070 /* }}} */
1071 
1072 /* {{{ curl_progress
1073  */
curl_progress(void * clientp,double dltotal,double dlnow,double ultotal,double ulnow)1074 static size_t curl_progress(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow)
1075 {
1076 	php_curl       *ch = (php_curl *) clientp;
1077 	php_curl_progress  *t  = ch->handlers->progress;
1078 	size_t	rval = 0;
1079 
1080 #if PHP_CURL_DEBUG
1081 	fprintf(stderr, "curl_progress() called\n");
1082 	fprintf(stderr, "clientp = %x, dltotal = %f, dlnow = %f, ultotal = %f, ulnow = %f\n", clientp, dltotal, dlnow, ultotal, ulnow);
1083 #endif
1084 
1085 	switch (t->method) {
1086 		case PHP_CURL_USER: {
1087 			zval **argv[4];
1088 			zval  *zdltotal = NULL;
1089 			zval  *zdlnow = NULL;
1090 			zval  *zultotal = NULL;
1091 			zval  *zulnow = NULL;
1092 			zval  *retval_ptr;
1093 			int   error;
1094 			zend_fcall_info fci;
1095 			TSRMLS_FETCH_FROM_CTX(ch->thread_ctx);
1096 
1097 			MAKE_STD_ZVAL(zdltotal);
1098 			MAKE_STD_ZVAL(zdlnow);
1099 			MAKE_STD_ZVAL(zultotal);
1100 			MAKE_STD_ZVAL(zulnow);
1101 
1102 			ZVAL_LONG(zdltotal, (long) dltotal);
1103 			ZVAL_LONG(zdlnow, (long) dlnow);
1104 			ZVAL_LONG(zultotal, (long) ultotal);
1105 			ZVAL_LONG(zulnow, (long) ulnow);
1106 
1107 			argv[0] = &zdltotal;
1108 			argv[1] = &zdlnow;
1109 			argv[2] = &zultotal;
1110 			argv[3] = &zulnow;
1111 
1112 			fci.size = sizeof(fci);
1113 			fci.function_table = EG(function_table);
1114 			fci.function_name = t->func_name;
1115 			fci.object_ptr = NULL;
1116 			fci.retval_ptr_ptr = &retval_ptr;
1117 			fci.param_count = 4;
1118 			fci.params = argv;
1119 			fci.no_separation = 0;
1120 			fci.symbol_table = NULL;
1121 
1122 			ch->in_callback = 1;
1123 			error = zend_call_function(&fci, &t->fci_cache TSRMLS_CC);
1124 			ch->in_callback = 0;
1125 			if (error == FAILURE) {
1126 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot call the CURLOPT_PROGRESSFUNCTION");
1127 			} else if (retval_ptr) {
1128 				_php_curl_verify_handlers(ch, 1 TSRMLS_CC);
1129 				if (Z_TYPE_P(retval_ptr) != IS_LONG) {
1130 					convert_to_long_ex(&retval_ptr);
1131 				}
1132 				if (0 != Z_LVAL_P(retval_ptr)) {
1133 					rval = 1;
1134 				}
1135 				zval_ptr_dtor(&retval_ptr);
1136 			}
1137 			zval_ptr_dtor(argv[0]);
1138 			zval_ptr_dtor(argv[1]);
1139 			zval_ptr_dtor(argv[2]);
1140 			zval_ptr_dtor(argv[3]);
1141 			break;
1142 		}
1143 	}
1144 	return rval;
1145 }
1146 /* }}} */
1147 
1148 /* {{{ curl_read
1149  */
curl_read(char * data,size_t size,size_t nmemb,void * ctx)1150 static size_t curl_read(char *data, size_t size, size_t nmemb, void *ctx)
1151 {
1152 	php_curl       *ch = (php_curl *) ctx;
1153 	php_curl_read  *t  = ch->handlers->read;
1154 	int             length = 0;
1155 
1156 	switch (t->method) {
1157 		case PHP_CURL_DIRECT:
1158 			if (t->fp) {
1159 				length = fread(data, size, nmemb, t->fp);
1160 			}
1161 			break;
1162 		case PHP_CURL_USER: {
1163 			zval **argv[3];
1164 			zval  *handle = NULL;
1165 			zval  *zfd = NULL;
1166 			zval  *zlength = NULL;
1167 			zval  *retval_ptr;
1168 			int   error;
1169 			zend_fcall_info fci;
1170 			TSRMLS_FETCH_FROM_CTX(ch->thread_ctx);
1171 
1172 			MAKE_STD_ZVAL(handle);
1173 			MAKE_STD_ZVAL(zfd);
1174 			MAKE_STD_ZVAL(zlength);
1175 
1176 			ZVAL_RESOURCE(handle, ch->id);
1177 			zend_list_addref(ch->id);
1178 			ZVAL_RESOURCE(zfd, t->fd);
1179 			zend_list_addref(t->fd);
1180 			ZVAL_LONG(zlength, (int) size * nmemb);
1181 
1182 			argv[0] = &handle;
1183 			argv[1] = &zfd;
1184 			argv[2] = &zlength;
1185 
1186 			fci.size = sizeof(fci);
1187 			fci.function_table = EG(function_table);
1188 			fci.function_name = t->func_name;
1189 			fci.object_ptr = NULL;
1190 			fci.retval_ptr_ptr = &retval_ptr;
1191 			fci.param_count = 3;
1192 			fci.params = argv;
1193 			fci.no_separation = 0;
1194 			fci.symbol_table = NULL;
1195 
1196 			ch->in_callback = 1;
1197 			error = zend_call_function(&fci, &t->fci_cache TSRMLS_CC);
1198 			ch->in_callback = 0;
1199 			if (error == FAILURE) {
1200 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot call the CURLOPT_READFUNCTION");
1201 #if LIBCURL_VERSION_NUM >= 0x070c01 /* 7.12.1 */
1202 				length = CURL_READFUNC_ABORT;
1203 #endif
1204 			} else if (retval_ptr) {
1205 				_php_curl_verify_handlers(ch, 1 TSRMLS_CC);
1206 				if (Z_TYPE_P(retval_ptr) == IS_STRING) {
1207 					length = MIN((int) (size * nmemb), Z_STRLEN_P(retval_ptr));
1208 					memcpy(data, Z_STRVAL_P(retval_ptr), length);
1209 				}
1210 				zval_ptr_dtor(&retval_ptr);
1211 			}
1212 
1213 			zval_ptr_dtor(argv[0]);
1214 			zval_ptr_dtor(argv[1]);
1215 			zval_ptr_dtor(argv[2]);
1216 			break;
1217 		}
1218 	}
1219 
1220 	return length;
1221 }
1222 /* }}} */
1223 
1224 /* {{{ curl_write_header
1225  */
curl_write_header(char * data,size_t size,size_t nmemb,void * ctx)1226 static size_t curl_write_header(char *data, size_t size, size_t nmemb, void *ctx)
1227 {
1228 	php_curl       *ch  = (php_curl *) ctx;
1229 	php_curl_write *t   = ch->handlers->write_header;
1230 	size_t          length = size * nmemb;
1231 	TSRMLS_FETCH_FROM_CTX(ch->thread_ctx);
1232 
1233 	switch (t->method) {
1234 		case PHP_CURL_STDOUT:
1235 			/* Handle special case write when we're returning the entire transfer
1236 			 */
1237 			if (ch->handlers->write->method == PHP_CURL_RETURN && length > 0) {
1238 				smart_str_appendl(&ch->handlers->write->buf, data, (int) length);
1239 			} else {
1240 				PHPWRITE(data, length);
1241 			}
1242 			break;
1243 		case PHP_CURL_FILE:
1244 			return fwrite(data, size, nmemb, t->fp);
1245 		case PHP_CURL_USER: {
1246 			zval **argv[2];
1247 			zval  *handle = NULL;
1248 			zval  *zdata = NULL;
1249 			zval  *retval_ptr;
1250 			int   error;
1251 			zend_fcall_info fci;
1252 
1253 			MAKE_STD_ZVAL(handle);
1254 			MAKE_STD_ZVAL(zdata);
1255 
1256 			ZVAL_RESOURCE(handle, ch->id);
1257 			zend_list_addref(ch->id);
1258 			ZVAL_STRINGL(zdata, data, length, 1);
1259 
1260 			argv[0] = &handle;
1261 			argv[1] = &zdata;
1262 
1263 			fci.size = sizeof(fci);
1264 			fci.function_table = EG(function_table);
1265 			fci.function_name = t->func_name;
1266 			fci.symbol_table = NULL;
1267 			fci.object_ptr = NULL;
1268 			fci.retval_ptr_ptr = &retval_ptr;
1269 			fci.param_count = 2;
1270 			fci.params = argv;
1271 			fci.no_separation = 0;
1272 
1273 			ch->in_callback = 1;
1274 			error = zend_call_function(&fci, &t->fci_cache TSRMLS_CC);
1275 			ch->in_callback = 0;
1276 			if (error == FAILURE) {
1277 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not call the CURLOPT_HEADERFUNCTION");
1278 				length = -1;
1279 			} else if (retval_ptr) {
1280 				_php_curl_verify_handlers(ch, 1 TSRMLS_CC);
1281 				if (Z_TYPE_P(retval_ptr) != IS_LONG) {
1282 					convert_to_long_ex(&retval_ptr);
1283 				}
1284 				length = Z_LVAL_P(retval_ptr);
1285 				zval_ptr_dtor(&retval_ptr);
1286 			}
1287 			zval_ptr_dtor(argv[0]);
1288 			zval_ptr_dtor(argv[1]);
1289 			break;
1290 		}
1291 
1292 		case PHP_CURL_IGNORE:
1293 			return length;
1294 
1295 		default:
1296 			return -1;
1297 	}
1298 
1299 	return length;
1300 }
1301 /* }}} */
1302 
curl_debug(CURL * cp,curl_infotype type,char * buf,size_t buf_len,void * ctx)1303 static int curl_debug(CURL *cp, curl_infotype type, char *buf, size_t buf_len, void *ctx) /* {{{ */
1304 {
1305 	php_curl    *ch   = (php_curl *) ctx;
1306 
1307 	if (type == CURLINFO_HEADER_OUT) {
1308 		if (ch->header.str_len) {
1309 			efree(ch->header.str);
1310 		}
1311 		if (buf_len > 0) {
1312 			ch->header.str = estrndup(buf, buf_len);
1313 			ch->header.str_len = buf_len;
1314 		}
1315 	}
1316 
1317 	return 0;
1318 }
1319 /* }}} */
1320 
1321 #if CURLOPT_PASSWDFUNCTION != 0
1322 /* {{{ curl_passwd
1323  */
curl_passwd(void * ctx,char * prompt,char * buf,int buflen)1324 static size_t curl_passwd(void *ctx, char *prompt, char *buf, int buflen)
1325 {
1326 	php_curl    *ch   = (php_curl *) ctx;
1327 	zval        *func = ch->handlers->passwd;
1328 	zval        *argv[3];
1329 	zval        *retval = NULL;
1330 	int          error;
1331 	int          ret = -1;
1332 	TSRMLS_FETCH_FROM_CTX(ch->thread_ctx);
1333 
1334 	MAKE_STD_ZVAL(argv[0]);
1335 	MAKE_STD_ZVAL(argv[1]);
1336 	MAKE_STD_ZVAL(argv[2]);
1337 
1338 	ZVAL_RESOURCE(argv[0], ch->id);
1339 	zend_list_addref(ch->id);
1340 	ZVAL_STRING(argv[1], prompt, 1);
1341 	ZVAL_LONG(argv[2], buflen);
1342 
1343 	error = call_user_function(EG(function_table), NULL, func, retval, 2, argv TSRMLS_CC);
1344 	if (error == FAILURE) {
1345 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not call the CURLOPT_PASSWDFUNCTION");
1346 	} else if (Z_TYPE_P(retval) == IS_STRING) {
1347 		if (Z_STRLEN_P(retval) > buflen) {
1348 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Returned password is too long for libcurl to handle");
1349 		} else {
1350 			strlcpy(buf, Z_STRVAL_P(retval), Z_STRLEN_P(retval));
1351 		}
1352 	} else {
1353 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "User handler '%s' did not return a string", Z_STRVAL_P(func));
1354 	}
1355 
1356 	zval_ptr_dtor(&argv[0]);
1357 	zval_ptr_dtor(&argv[1]);
1358 	zval_ptr_dtor(&argv[2]);
1359 	zval_ptr_dtor(&retval);
1360 
1361 	return ret;
1362 }
1363 /* }}} */
1364 #endif
1365 
1366 /* {{{ curl_free_string
1367  */
curl_free_string(void ** string)1368 static void curl_free_string(void **string)
1369 {
1370 	efree(*string);
1371 }
1372 /* }}} */
1373 
1374 /* {{{ curl_free_post
1375  */
curl_free_post(void ** post)1376 static void curl_free_post(void **post)
1377 {
1378 	curl_formfree((struct HttpPost *) *post);
1379 }
1380 /* }}} */
1381 
1382 /* {{{ curl_free_slist
1383  */
curl_free_slist(void * slist)1384 static void curl_free_slist(void *slist)
1385 {
1386 	curl_slist_free_all(*((struct curl_slist **) slist));
1387 }
1388 /* }}} */
1389 
1390 /* {{{ proto array curl_version([int version])
1391    Return cURL version information. */
PHP_FUNCTION(curl_version)1392 PHP_FUNCTION(curl_version)
1393 {
1394 	curl_version_info_data *d;
1395 	long uversion = CURLVERSION_NOW;
1396 
1397 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &uversion) == FAILURE) {
1398 		return;
1399 	}
1400 
1401 	d = curl_version_info(uversion);
1402 	if (d == NULL) {
1403 		RETURN_FALSE;
1404 	}
1405 
1406 	array_init(return_value);
1407 
1408 	CAAL("version_number", d->version_num);
1409 	CAAL("age", d->age);
1410 	CAAL("features", d->features);
1411 	CAAL("ssl_version_number", d->ssl_version_num);
1412 	CAAS("version", d->version);
1413 	CAAS("host", d->host);
1414 	CAAS("ssl_version", d->ssl_version);
1415 	CAAS("libz_version", d->libz_version);
1416 	/* Add an array of protocols */
1417 	{
1418 		char **p = (char **) d->protocols;
1419 		zval  *protocol_list = NULL;
1420 
1421 		MAKE_STD_ZVAL(protocol_list);
1422 		array_init(protocol_list);
1423 
1424 		while (*p != NULL) {
1425 			add_next_index_string(protocol_list, *p, 1);
1426 			p++;
1427 		}
1428 		CAAZ("protocols", protocol_list);
1429 	}
1430 }
1431 /* }}} */
1432 
1433 /* {{{ alloc_curl_handle
1434  */
alloc_curl_handle(php_curl ** ch)1435 static void alloc_curl_handle(php_curl **ch)
1436 {
1437 	*ch                           = emalloc(sizeof(php_curl));
1438 	(*ch)->to_free                = ecalloc(1, sizeof(struct _php_curl_free));
1439 	(*ch)->handlers               = ecalloc(1, sizeof(php_curl_handlers));
1440 	(*ch)->handlers->write        = ecalloc(1, sizeof(php_curl_write));
1441 	(*ch)->handlers->write_header = ecalloc(1, sizeof(php_curl_write));
1442 	(*ch)->handlers->read         = ecalloc(1, sizeof(php_curl_read));
1443 	(*ch)->handlers->progress     = ecalloc(1, sizeof(php_curl_progress));
1444 
1445 	(*ch)->in_callback = 0;
1446 	(*ch)->header.str_len = 0;
1447 
1448 	memset(&(*ch)->err, 0, sizeof((*ch)->err));
1449 	(*ch)->handlers->write->stream = NULL;
1450 	(*ch)->handlers->write_header->stream = NULL;
1451 	(*ch)->handlers->read->stream = NULL;
1452 
1453 	zend_llist_init(&(*ch)->to_free->str,   sizeof(char *),            (llist_dtor_func_t) curl_free_string, 0);
1454 	zend_llist_init(&(*ch)->to_free->post,  sizeof(struct HttpPost),   (llist_dtor_func_t) curl_free_post,   0);
1455 
1456 	(*ch)->to_free->slist = emalloc(sizeof(HashTable));
1457 	zend_hash_init((*ch)->to_free->slist, 4, NULL, curl_free_slist, 0);
1458 }
1459 /* }}} */
1460 
1461 #if LIBCURL_VERSION_NUM > 0x071301
1462 /* {{{ split_certinfo
1463  */
split_certinfo(char * string,zval * hash)1464 static void split_certinfo(char *string, zval *hash)
1465 {
1466 	char *org = estrdup(string);
1467 	char *s = org;
1468 	char *split;
1469 
1470 	if(org) {
1471         do {
1472 			char *key;
1473 			char *val;
1474 			char *tmp;
1475 
1476             split = strstr(s, "; ");
1477             if(split)
1478                 *split = '\0';
1479 
1480 			key = s;
1481 			tmp = memchr(key, '=', 64);
1482 			if(tmp) {
1483 				*tmp = '\0';
1484 				val = tmp+1;
1485 				add_assoc_string(hash, key, val, 1);
1486 			}
1487 			s = split+2;
1488 		} while(split);
1489 		efree(org);
1490 	}
1491 }
1492 /* }}} */
1493 
1494 /* {{{ create_certinfo
1495  */
create_certinfo(struct curl_certinfo * ci,zval * listcode TSRMLS_DC)1496 static void create_certinfo(struct curl_certinfo *ci, zval *listcode TSRMLS_DC)
1497 {
1498 	int i;
1499 
1500 	if(ci) {
1501 		zval *certhash = NULL;
1502 
1503 		for(i=0; i<ci->num_of_certs; i++) {
1504 			struct curl_slist *slist;
1505 
1506 			MAKE_STD_ZVAL(certhash);
1507 			array_init(certhash);
1508 			for(slist = ci->certinfo[i]; slist; slist = slist->next) {
1509 				int len;
1510 				char s[64];
1511 				char *tmp;
1512 				strncpy(s, slist->data, 64);
1513 				tmp = memchr(s, ':', 64);
1514 				if(tmp) {
1515 					*tmp = '\0';
1516 					len = strlen(s);
1517 					if(!strcmp(s, "Subject") || !strcmp(s, "Issuer")) {
1518 						zval *hash;
1519 
1520 						MAKE_STD_ZVAL(hash);
1521 						array_init(hash);
1522 
1523 						split_certinfo(&slist->data[len+1], hash);
1524 						add_assoc_zval(certhash, s, hash);
1525 					} else {
1526 						add_assoc_string(certhash, s, &slist->data[len+1], 1);
1527 					}
1528 				} else {
1529 					php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not extract hash key from certificate info");
1530 				}
1531 			}
1532 			add_next_index_zval(listcode, certhash);
1533 		}
1534 	}
1535 }
1536 /* }}} */
1537 #endif
1538 
1539 /* {{{ proto resource curl_init([string url])
1540    Initialize a cURL session */
PHP_FUNCTION(curl_init)1541 PHP_FUNCTION(curl_init)
1542 {
1543 	php_curl	*ch;
1544 	CURL		*cp;
1545 	zval		*clone;
1546 	char		*url = NULL;
1547 	int		url_len = 0;
1548 	char *cainfo;
1549 
1550 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &url, &url_len) == FAILURE) {
1551 		return;
1552 	}
1553 
1554 	cp = curl_easy_init();
1555 	if (!cp) {
1556 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not initialize a new cURL handle");
1557 		RETURN_FALSE;
1558 	}
1559 
1560 	alloc_curl_handle(&ch);
1561 	TSRMLS_SET_CTX(ch->thread_ctx);
1562 
1563 	ch->cp = cp;
1564 
1565 	ch->handlers->write->method = PHP_CURL_STDOUT;
1566 	ch->handlers->write->type   = PHP_CURL_ASCII;
1567 	ch->handlers->read->method  = PHP_CURL_DIRECT;
1568 	ch->handlers->write_header->method = PHP_CURL_IGNORE;
1569 
1570 	ch->uses = 0;
1571 
1572 	MAKE_STD_ZVAL(clone);
1573 	ch->clone = clone;
1574 
1575 	curl_easy_setopt(ch->cp, CURLOPT_NOPROGRESS,        1);
1576 	curl_easy_setopt(ch->cp, CURLOPT_VERBOSE,           0);
1577 	curl_easy_setopt(ch->cp, CURLOPT_ERRORBUFFER,       ch->err.str);
1578 	curl_easy_setopt(ch->cp, CURLOPT_WRITEFUNCTION,     curl_write);
1579 	curl_easy_setopt(ch->cp, CURLOPT_FILE,              (void *) ch);
1580 	curl_easy_setopt(ch->cp, CURLOPT_READFUNCTION,      curl_read);
1581 	curl_easy_setopt(ch->cp, CURLOPT_INFILE,            (void *) ch);
1582 	curl_easy_setopt(ch->cp, CURLOPT_HEADERFUNCTION,    curl_write_header);
1583 	curl_easy_setopt(ch->cp, CURLOPT_WRITEHEADER,       (void *) ch);
1584 	curl_easy_setopt(ch->cp, CURLOPT_DNS_USE_GLOBAL_CACHE, 1);
1585 	curl_easy_setopt(ch->cp, CURLOPT_DNS_CACHE_TIMEOUT, 120);
1586 	curl_easy_setopt(ch->cp, CURLOPT_MAXREDIRS, 20); /* prevent infinite redirects */
1587 
1588 	cainfo = INI_STR("curl.cainfo");
1589 	if (cainfo && strlen(cainfo) > 0) {
1590 		curl_easy_setopt(ch->cp, CURLOPT_CAINFO, cainfo);
1591 	}
1592 
1593 #if defined(ZTS)
1594 	curl_easy_setopt(ch->cp, CURLOPT_NOSIGNAL, 1);
1595 #endif
1596 
1597 	if (url) {
1598 		if (!php_curl_option_url(ch, url, url_len TSRMLS_CC)) {
1599 			_php_curl_close_ex(ch TSRMLS_CC);
1600 			RETURN_FALSE;
1601 		}
1602 	}
1603 
1604 	ZEND_REGISTER_RESOURCE(return_value, ch, le_curl);
1605 	ch->id = Z_LVAL_P(return_value);
1606 }
1607 /* }}} */
1608 
1609 /* {{{ proto resource curl_copy_handle(resource ch)
1610    Copy a cURL handle along with all of it's preferences */
PHP_FUNCTION(curl_copy_handle)1611 PHP_FUNCTION(curl_copy_handle)
1612 {
1613 	CURL		*cp;
1614 	zval		*zid;
1615 	php_curl	*ch, *dupch;
1616 
1617 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zid) == FAILURE) {
1618 		return;
1619 	}
1620 
1621 	ZEND_FETCH_RESOURCE(ch, php_curl *, &zid, -1, le_curl_name, le_curl);
1622 
1623 	cp = curl_easy_duphandle(ch->cp);
1624 	if (!cp) {
1625 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot duplicate cURL handle");
1626 		RETURN_FALSE;
1627 	}
1628 
1629 	alloc_curl_handle(&dupch);
1630 	TSRMLS_SET_CTX(dupch->thread_ctx);
1631 
1632 	dupch->cp = cp;
1633 	dupch->uses = 0;
1634 	ch->uses++;
1635 	if (ch->handlers->write->stream) {
1636 		Z_ADDREF_P(ch->handlers->write->stream);
1637 	}
1638 	dupch->handlers->write->stream = ch->handlers->write->stream;
1639 	dupch->handlers->write->method = ch->handlers->write->method;
1640 	dupch->handlers->write->type   = ch->handlers->write->type;
1641 	if (ch->handlers->read->stream) {
1642 		Z_ADDREF_P(ch->handlers->read->stream);
1643 	}
1644 	dupch->handlers->read->stream  = ch->handlers->read->stream;
1645 	dupch->handlers->read->method  = ch->handlers->read->method;
1646 	dupch->handlers->write_header->method = ch->handlers->write_header->method;
1647 	if (ch->handlers->write_header->stream) {
1648 		Z_ADDREF_P(ch->handlers->write_header->stream);
1649 	}
1650 	dupch->handlers->write_header->stream = ch->handlers->write_header->stream;
1651 
1652 	dupch->handlers->write->fp = ch->handlers->write->fp;
1653 	dupch->handlers->write_header->fp = ch->handlers->write_header->fp;
1654 	dupch->handlers->read->fp = ch->handlers->read->fp;
1655 	dupch->handlers->read->fd = ch->handlers->read->fd;
1656 #if CURLOPT_PASSWDDATA != 0
1657 	if (ch->handlers->passwd) {
1658 		zval_add_ref(&ch->handlers->passwd);
1659 		dupch->handlers->passwd = ch->handlers->passwd;
1660 		curl_easy_setopt(ch->cp, CURLOPT_PASSWDDATA, (void *) dupch);
1661 	}
1662 #endif
1663 	if (ch->handlers->write->func_name) {
1664 		zval_add_ref(&ch->handlers->write->func_name);
1665 		dupch->handlers->write->func_name = ch->handlers->write->func_name;
1666 	}
1667 	if (ch->handlers->read->func_name) {
1668 		zval_add_ref(&ch->handlers->read->func_name);
1669 		dupch->handlers->read->func_name = ch->handlers->read->func_name;
1670 	}
1671 	if (ch->handlers->write_header->func_name) {
1672 		zval_add_ref(&ch->handlers->write_header->func_name);
1673 		dupch->handlers->write_header->func_name = ch->handlers->write_header->func_name;
1674 	}
1675 
1676 	if (ch->handlers->progress->func_name) {
1677 		zval_add_ref(&ch->handlers->progress->func_name);
1678 		dupch->handlers->progress->func_name = ch->handlers->progress->func_name;
1679 	}
1680 	dupch->handlers->progress->method = ch->handlers->progress->method;
1681 
1682 	curl_easy_setopt(dupch->cp, CURLOPT_ERRORBUFFER,       dupch->err.str);
1683 	curl_easy_setopt(dupch->cp, CURLOPT_FILE,              (void *) dupch);
1684 	curl_easy_setopt(dupch->cp, CURLOPT_INFILE,            (void *) dupch);
1685 	curl_easy_setopt(dupch->cp, CURLOPT_WRITEHEADER,       (void *) dupch);
1686 	curl_easy_setopt(dupch->cp, CURLOPT_PROGRESSDATA,      (void *) dupch);
1687 
1688 	efree(dupch->to_free->slist);
1689 	efree(dupch->to_free);
1690 	dupch->to_free = ch->to_free;
1691 
1692 	/* Keep track of cloned copies to avoid invoking curl destructors for every clone */
1693 	Z_ADDREF_P(ch->clone);
1694 	dupch->clone = ch->clone;
1695 
1696 	ZEND_REGISTER_RESOURCE(return_value, dupch, le_curl);
1697 	dupch->id = Z_LVAL_P(return_value);
1698 }
1699 /* }}} */
1700 
_php_curl_setopt(php_curl * ch,long option,zval ** zvalue,zval * return_value TSRMLS_DC)1701 static int _php_curl_setopt(php_curl *ch, long option, zval **zvalue, zval *return_value TSRMLS_DC) /* {{{ */
1702 {
1703 	CURLcode     error=CURLE_OK;
1704 
1705 	switch (option) {
1706 		/* Long options */
1707 		case CURLOPT_SSL_VERIFYHOST:
1708 			if(Z_BVAL_PP(zvalue) == 1) {
1709 #if LIBCURL_VERSION_NUM <= 0x071c00 /* 7.28.0 */
1710 				php_error_docref(NULL TSRMLS_CC, E_NOTICE, "CURLOPT_SSL_VERIFYHOST with value 1 is deprecated and will be removed as of libcurl 7.28.1. It is recommended to use value 2 instead");
1711 #else
1712 				php_error_docref(NULL TSRMLS_CC, E_NOTICE, "CURLOPT_SSL_VERIFYHOST no longer accepts the value 1, value 2 will be used instead");
1713 				error = curl_easy_setopt(ch->cp, option, 2);
1714 				break;
1715 #endif
1716 			}
1717 		case CURLOPT_INFILESIZE:
1718 		case CURLOPT_VERBOSE:
1719 		case CURLOPT_HEADER:
1720 		case CURLOPT_NOPROGRESS:
1721 		case CURLOPT_NOBODY:
1722 		case CURLOPT_FAILONERROR:
1723 		case CURLOPT_UPLOAD:
1724 		case CURLOPT_POST:
1725 		case CURLOPT_FTPLISTONLY:
1726 		case CURLOPT_FTPAPPEND:
1727 		case CURLOPT_NETRC:
1728 		case CURLOPT_PUT:
1729 #if CURLOPT_MUTE != 0
1730 		 case CURLOPT_MUTE:
1731 #endif
1732 		case CURLOPT_TIMEOUT:
1733 #if LIBCURL_VERSION_NUM > 0x071002
1734 		case CURLOPT_TIMEOUT_MS:
1735 #endif
1736 		case CURLOPT_FTP_USE_EPSV:
1737 		case CURLOPT_LOW_SPEED_LIMIT:
1738 		case CURLOPT_SSLVERSION:
1739 		case CURLOPT_LOW_SPEED_TIME:
1740 		case CURLOPT_RESUME_FROM:
1741 		case CURLOPT_TIMEVALUE:
1742 		case CURLOPT_TIMECONDITION:
1743 		case CURLOPT_TRANSFERTEXT:
1744 		case CURLOPT_HTTPPROXYTUNNEL:
1745 		case CURLOPT_FILETIME:
1746 		case CURLOPT_MAXREDIRS:
1747 		case CURLOPT_MAXCONNECTS:
1748 		case CURLOPT_CLOSEPOLICY:
1749 		case CURLOPT_FRESH_CONNECT:
1750 		case CURLOPT_FORBID_REUSE:
1751 		case CURLOPT_CONNECTTIMEOUT:
1752 #if LIBCURL_VERSION_NUM > 0x071002
1753 		case CURLOPT_CONNECTTIMEOUT_MS:
1754 #endif
1755 		case CURLOPT_SSL_VERIFYPEER:
1756 		case CURLOPT_DNS_USE_GLOBAL_CACHE:
1757 		case CURLOPT_NOSIGNAL:
1758 		case CURLOPT_PROXYTYPE:
1759 		case CURLOPT_BUFFERSIZE:
1760 		case CURLOPT_HTTPGET:
1761 		case CURLOPT_HTTP_VERSION:
1762 		case CURLOPT_CRLF:
1763 		case CURLOPT_DNS_CACHE_TIMEOUT:
1764 		case CURLOPT_PROXYPORT:
1765 		case CURLOPT_FTP_USE_EPRT:
1766 #if LIBCURL_VERSION_NUM > 0x070a05 /* CURLOPT_HTTPAUTH is available since curl 7.10.6 */
1767 		case CURLOPT_HTTPAUTH:
1768 #endif
1769 #if LIBCURL_VERSION_NUM > 0x070a06 /* CURLOPT_PROXYAUTH & CURLOPT_FTP_CREATE_MISSING_DIRS are available since curl 7.10.7 */
1770 		case CURLOPT_PROXYAUTH:
1771 		case CURLOPT_FTP_CREATE_MISSING_DIRS:
1772 #endif
1773 
1774 #if LIBCURL_VERSION_NUM >= 0x070c02
1775 		case CURLOPT_FTPSSLAUTH:
1776 #endif
1777 #if LIBCURL_VERSION_NUM >  0x070b00
1778 		case CURLOPT_FTP_SSL:
1779 #endif
1780 		case CURLOPT_UNRESTRICTED_AUTH:
1781 		case CURLOPT_PORT:
1782 		case CURLOPT_AUTOREFERER:
1783 		case CURLOPT_COOKIESESSION:
1784 #if LIBCURL_VERSION_NUM > 0x070b01 /* CURLOPT_TCP_NODELAY is available since curl 7.11.2 */
1785 		case CURLOPT_TCP_NODELAY:
1786 #endif
1787 #if LIBCURL_VERSION_NUM >= 0x71304
1788 		case CURLOPT_REDIR_PROTOCOLS:
1789 		case CURLOPT_PROTOCOLS:
1790 #endif
1791 #if LIBCURL_VERSION_NUM > 0x070a07 /* CURLOPT_IPRESOLVE is available since curl 7.10.8 */
1792 		case CURLOPT_IPRESOLVE:
1793 #endif
1794 #if LIBCURL_VERSION_NUM >= 0x070f01
1795 		case CURLOPT_FTP_FILEMETHOD:
1796 		case CURLOPT_FTP_SKIP_PASV_IP:
1797 #endif
1798 #if LIBCURL_VERSION_NUM >  0x071301
1799 		case CURLOPT_CERTINFO:
1800 #endif
1801 			convert_to_long_ex(zvalue);
1802 #if LIBCURL_VERSION_NUM >= 0x71304
1803 			if ((option == CURLOPT_PROTOCOLS || option == CURLOPT_REDIR_PROTOCOLS) &&
1804 				(PG(open_basedir) && *PG(open_basedir)) && (Z_LVAL_PP(zvalue) & CURLPROTO_FILE)) {
1805 					php_error_docref(NULL TSRMLS_CC, E_WARNING, "CURLPROTO_FILE cannot be activated when an open_basedir is set");
1806 					RETVAL_FALSE;
1807 					return 1;
1808 			}
1809 #endif
1810 			error = curl_easy_setopt(ch->cp, option, Z_LVAL_PP(zvalue));
1811 			break;
1812 #if LIBCURL_VERSION_NUM > 0x070f04
1813 		case CURLOPT_MAX_RECV_SPEED_LARGE:
1814 		case CURLOPT_MAX_SEND_SPEED_LARGE:
1815 			convert_to_long_ex(zvalue);
1816 			error = curl_easy_setopt(ch->cp, option, (curl_off_t)Z_LVAL_PP(zvalue));
1817 			break;
1818 #endif
1819 		case CURLOPT_FOLLOWLOCATION:
1820 			convert_to_long_ex(zvalue);
1821 			if (PG(open_basedir) && *PG(open_basedir)) {
1822 				if (Z_LVAL_PP(zvalue) != 0) {
1823 					php_error_docref(NULL TSRMLS_CC, E_WARNING, "CURLOPT_FOLLOWLOCATION cannot be activated when an open_basedir is set");
1824 					RETVAL_FALSE;
1825 					return 1;
1826 				}
1827 			}
1828 			error = curl_easy_setopt(ch->cp, option, Z_LVAL_PP(zvalue));
1829 			break;
1830 #if LIBCURL_VERSION_NUM > 0x071301
1831 		case CURLOPT_POSTREDIR:
1832 			convert_to_long_ex(zvalue);
1833 			error = curl_easy_setopt(ch->cp, CURLOPT_POSTREDIR, Z_LVAL_PP(zvalue) & CURL_REDIR_POST_ALL);
1834 			break;
1835 #endif
1836 		case CURLOPT_PRIVATE:
1837 		case CURLOPT_URL:
1838 		case CURLOPT_PROXY:
1839 		case CURLOPT_USERPWD:
1840 		case CURLOPT_PROXYUSERPWD:
1841 		case CURLOPT_RANGE:
1842 		case CURLOPT_CUSTOMREQUEST:
1843 		case CURLOPT_USERAGENT:
1844 		case CURLOPT_FTPPORT:
1845 		case CURLOPT_COOKIE:
1846 		case CURLOPT_REFERER:
1847 		case CURLOPT_INTERFACE:
1848 		case CURLOPT_KRB4LEVEL:
1849 		case CURLOPT_EGDSOCKET:
1850 		case CURLOPT_CAINFO:
1851 		case CURLOPT_CAPATH:
1852 		case CURLOPT_SSL_CIPHER_LIST:
1853 		case CURLOPT_SSLKEY:
1854 		case CURLOPT_SSLKEYTYPE:
1855 		case CURLOPT_SSLKEYPASSWD:
1856 		case CURLOPT_SSLENGINE:
1857 		case CURLOPT_SSLENGINE_DEFAULT:
1858 		case CURLOPT_SSLCERTTYPE:
1859 		case CURLOPT_ENCODING:
1860 #if LIBCURL_VERSION_NUM >= 0x071300
1861 		case CURLOPT_SSH_PUBLIC_KEYFILE:
1862 		case CURLOPT_SSH_PRIVATE_KEYFILE:
1863 #endif
1864 		{
1865 			convert_to_string_ex(zvalue);
1866 #if LIBCURL_VERSION_NUM >= 0x071300
1867 			if (
1868 				option == CURLOPT_SSH_PUBLIC_KEYFILE || option == CURLOPT_SSH_PRIVATE_KEYFILE
1869 
1870 			) {
1871 				if (php_check_open_basedir(Z_STRVAL_PP(zvalue) TSRMLS_CC)) {
1872 					RETVAL_FALSE;
1873 					return 1;
1874 				}
1875 			}
1876 #endif
1877 			if (option == CURLOPT_URL) {
1878 				if (!php_curl_option_url(ch, Z_STRVAL_PP(zvalue), Z_STRLEN_PP(zvalue) TSRMLS_CC)) {
1879 					RETVAL_FALSE;
1880 					return 1;
1881 				}
1882 			} else {
1883 				if (option == CURLOPT_PRIVATE) {
1884 					char *copystr;
1885 #if LIBCURL_VERSION_NUM < 0x071100
1886 string_copy:
1887 #endif
1888 					copystr = estrndup(Z_STRVAL_PP(zvalue), Z_STRLEN_PP(zvalue));
1889 					error = curl_easy_setopt(ch->cp, option, copystr);
1890 					zend_llist_add_element(&ch->to_free->str, &copystr);
1891 				} else {
1892 #if LIBCURL_VERSION_NUM >= 0x071100
1893 					/* Strings passed to libcurl as ’char *’ arguments, are copied by the library... NOTE: before 7.17.0 strings were not copied. */
1894 					error = curl_easy_setopt(ch->cp, option, Z_STRVAL_PP(zvalue));
1895 #else
1896 					goto string_copy;
1897 #endif
1898 				}
1899 			}
1900 			break;
1901 		}
1902 		case CURLOPT_FILE:
1903 		case CURLOPT_INFILE:
1904 		case CURLOPT_WRITEHEADER:
1905 		case CURLOPT_STDERR: {
1906 			FILE *fp = NULL;
1907 			int type;
1908 			void * what;
1909 
1910 			what = zend_fetch_resource(zvalue TSRMLS_CC, -1, "File-Handle", &type, 1, php_file_le_stream(), php_file_le_pstream());
1911 			if (!what) {
1912 				RETVAL_FALSE;
1913 				return 1;
1914 			}
1915 
1916 			if (FAILURE == php_stream_cast((php_stream *) what, PHP_STREAM_AS_STDIO, (void *) &fp, REPORT_ERRORS)) {
1917 				RETVAL_FALSE;
1918 				return 1;
1919 			}
1920 
1921 			if (!fp) {
1922 				RETVAL_FALSE;
1923 				return 1;
1924 			}
1925 
1926 			error = CURLE_OK;
1927 			switch (option) {
1928 				case CURLOPT_FILE:
1929 					if (((php_stream *) what)->mode[0] != 'r' || ((php_stream *) what)->mode[1] == '+') {
1930 						if (ch->handlers->write->stream) {
1931 							Z_DELREF_P(ch->handlers->write->stream);
1932 						}
1933 						Z_ADDREF_PP(zvalue);
1934 						ch->handlers->write->fp = fp;
1935 						ch->handlers->write->method = PHP_CURL_FILE;
1936 						ch->handlers->write->stream = *zvalue;
1937 					} else {
1938 						php_error_docref(NULL TSRMLS_CC, E_WARNING, "the provided file handle is not writable");
1939 						RETVAL_FALSE;
1940 						return 1;
1941 					}
1942 					break;
1943 				case CURLOPT_WRITEHEADER:
1944 					if (((php_stream *) what)->mode[0] != 'r' || ((php_stream *) what)->mode[1] == '+') {
1945 						if (ch->handlers->write_header->stream) {
1946 							Z_DELREF_P(ch->handlers->write_header->stream);
1947 						}
1948 						Z_ADDREF_PP(zvalue);
1949 						ch->handlers->write_header->fp = fp;
1950 						ch->handlers->write_header->method = PHP_CURL_FILE;
1951 						ch->handlers->write_header->stream = *zvalue;
1952 					} else {
1953 						php_error_docref(NULL TSRMLS_CC, E_WARNING, "the provided file handle is not writable");
1954 						RETVAL_FALSE;
1955 						return 1;
1956 					}
1957 					break;
1958 				case CURLOPT_INFILE:
1959 					if (ch->handlers->read->stream) {
1960 						Z_DELREF_P(ch->handlers->read->stream);
1961 					}
1962 					Z_ADDREF_PP(zvalue);
1963 					ch->handlers->read->fp = fp;
1964 					ch->handlers->read->fd = Z_LVAL_PP(zvalue);
1965 					ch->handlers->read->stream = *zvalue;
1966 					break;
1967 				case CURLOPT_STDERR:
1968 					if (((php_stream *) what)->mode[0] != 'r' || ((php_stream *) what)->mode[1] == '+') {
1969 						if (ch->handlers->std_err) {
1970 							zval_ptr_dtor(&ch->handlers->std_err);
1971 						}
1972 						zval_add_ref(zvalue);
1973 						ch->handlers->std_err = *zvalue;
1974 					} else {
1975 						php_error_docref(NULL TSRMLS_CC, E_WARNING, "the provided file handle is not writable");
1976 						RETVAL_FALSE;
1977 						return 1;
1978 					}
1979 					/* break omitted intentionally */
1980 				default:
1981 					error = curl_easy_setopt(ch->cp, option, fp);
1982 					break;
1983 			}
1984 
1985 			break;
1986 		}
1987 		case CURLOPT_RETURNTRANSFER:
1988 			convert_to_long_ex(zvalue);
1989 
1990 			if (Z_LVAL_PP(zvalue)) {
1991 				ch->handlers->write->method = PHP_CURL_RETURN;
1992 			} else {
1993 				ch->handlers->write->method = PHP_CURL_STDOUT;
1994 			}
1995 			break;
1996 		case CURLOPT_BINARYTRANSFER:
1997 			convert_to_long_ex(zvalue);
1998 
1999 			if (Z_LVAL_PP(zvalue)) {
2000 				ch->handlers->write->type = PHP_CURL_BINARY;
2001 			} else {
2002 				ch->handlers->write->type = PHP_CURL_ASCII;
2003 			}
2004 			break;
2005 		case CURLOPT_WRITEFUNCTION:
2006 			if (ch->handlers->write->func_name) {
2007 				zval_ptr_dtor(&ch->handlers->write->func_name);
2008 				ch->handlers->write->fci_cache = empty_fcall_info_cache;
2009 			}
2010 			zval_add_ref(zvalue);
2011 			ch->handlers->write->func_name = *zvalue;
2012 			ch->handlers->write->method = PHP_CURL_USER;
2013 			break;
2014 		case CURLOPT_READFUNCTION:
2015 			if (ch->handlers->read->func_name) {
2016 				zval_ptr_dtor(&ch->handlers->read->func_name);
2017 				ch->handlers->read->fci_cache = empty_fcall_info_cache;
2018 			}
2019 			zval_add_ref(zvalue);
2020 			ch->handlers->read->func_name = *zvalue;
2021 			ch->handlers->read->method = PHP_CURL_USER;
2022 			break;
2023 		case CURLOPT_PROGRESSFUNCTION:
2024 			curl_easy_setopt(ch->cp, CURLOPT_PROGRESSFUNCTION,	curl_progress);
2025 			curl_easy_setopt(ch->cp, CURLOPT_PROGRESSDATA, ch);
2026 			if (ch->handlers->progress->func_name) {
2027 				zval_ptr_dtor(&ch->handlers->progress->func_name);
2028 				ch->handlers->progress->fci_cache = empty_fcall_info_cache;
2029 			}
2030 			zval_add_ref(zvalue);
2031 			ch->handlers->progress->func_name = *zvalue;
2032 			ch->handlers->progress->method = PHP_CURL_USER;
2033 			break;
2034 		case CURLOPT_HEADERFUNCTION:
2035 			if (ch->handlers->write_header->func_name) {
2036 				zval_ptr_dtor(&ch->handlers->write_header->func_name);
2037 				ch->handlers->write_header->fci_cache = empty_fcall_info_cache;
2038 			}
2039 			zval_add_ref(zvalue);
2040 			ch->handlers->write_header->func_name = *zvalue;
2041 			ch->handlers->write_header->method = PHP_CURL_USER;
2042 			break;
2043 #if CURLOPT_PASSWDFUNCTION != 0
2044 		case CURLOPT_PASSWDFUNCTION:
2045 			if (ch->handlers->passwd) {
2046 				zval_ptr_dtor(&ch->handlers->passwd);
2047 			}
2048 			zval_add_ref(zvalue);
2049 			ch->handlers->passwd = *zvalue;
2050 			error = curl_easy_setopt(ch->cp, CURLOPT_PASSWDFUNCTION, curl_passwd);
2051 			error = curl_easy_setopt(ch->cp, CURLOPT_PASSWDDATA,     (void *) ch);
2052 			break;
2053 #endif
2054 		case CURLOPT_POSTFIELDS:
2055 			if (Z_TYPE_PP(zvalue) == IS_ARRAY || Z_TYPE_PP(zvalue) == IS_OBJECT) {
2056 				zval            **current;
2057 				HashTable        *postfields;
2058 				struct HttpPost  *first = NULL;
2059 				struct HttpPost  *last  = NULL;
2060 
2061 				postfields = HASH_OF(*zvalue);
2062 				if (!postfields) {
2063 					php_error_docref(NULL TSRMLS_CC, E_WARNING, "Couldn't get HashTable in CURLOPT_POSTFIELDS");
2064 					RETVAL_FALSE;
2065 					return 1;
2066 				}
2067 
2068 				for (zend_hash_internal_pointer_reset(postfields);
2069 					 zend_hash_get_current_data(postfields, (void **) &current) == SUCCESS;
2070 					 zend_hash_move_forward(postfields)
2071 				) {
2072 					char *postval;
2073 					char *string_key = NULL;
2074 					uint  string_key_len;
2075 					ulong num_key;
2076 					int numeric_key;
2077 
2078 					SEPARATE_ZVAL(current);
2079 					convert_to_string_ex(current);
2080 
2081 					zend_hash_get_current_key_ex(postfields, &string_key, &string_key_len, &num_key, 0, NULL);
2082 
2083 					/* Pretend we have a string_key here */
2084 					if(!string_key) {
2085 						spprintf(&string_key, 0, "%ld", num_key);
2086 						string_key_len = strlen(string_key)+1;
2087 						numeric_key = 1;
2088 					} else {
2089 						numeric_key = 0;
2090 					}
2091 
2092 					postval = Z_STRVAL_PP(current);
2093 
2094 					/* The arguments after _NAMELENGTH and _CONTENTSLENGTH
2095 					 * must be explicitly cast to long in curl_formadd
2096 					 * use since curl needs a long not an int. */
2097 					if (*postval == '@') {
2098 						char *type, *filename;
2099 						++postval;
2100 
2101 						if ((type = php_memnstr(postval, ";type=", sizeof(";type=") - 1, postval + Z_STRLEN_PP(current)))) {
2102 							*type = '\0';
2103 						}
2104 						if ((filename = php_memnstr(postval, ";filename=", sizeof(";filename=") - 1, postval + Z_STRLEN_PP(current)))) {
2105 							*filename = '\0';
2106 						}
2107 						/* open_basedir check */
2108 						if (php_check_open_basedir(postval TSRMLS_CC)) {
2109 							RETVAL_FALSE;
2110 							return 1;
2111 						}
2112 						error = curl_formadd(&first, &last,
2113 										CURLFORM_COPYNAME, string_key,
2114 										CURLFORM_NAMELENGTH, (long)string_key_len - 1,
2115 										CURLFORM_FILENAME, filename ? filename + sizeof(";filename=") - 1 : postval,
2116 										CURLFORM_CONTENTTYPE, type ? type + sizeof(";type=") - 1 : "application/octet-stream",
2117 										CURLFORM_FILE, postval,
2118 										CURLFORM_END);
2119 						if (type) {
2120 							*type = ';';
2121 						}
2122 						if (filename) {
2123 							*filename = ';';
2124 						}
2125 					} else {
2126 						error = curl_formadd(&first, &last,
2127 											 CURLFORM_COPYNAME, string_key,
2128 											 CURLFORM_NAMELENGTH, (long)string_key_len - 1,
2129 											 CURLFORM_COPYCONTENTS, postval,
2130 											 CURLFORM_CONTENTSLENGTH, (long)Z_STRLEN_PP(current),
2131 											 CURLFORM_END);
2132 					}
2133 
2134 					if (numeric_key) {
2135 						efree(string_key);
2136 					}
2137 				}
2138 
2139 				SAVE_CURL_ERROR(ch, error);
2140 				if (error != CURLE_OK) {
2141 					RETVAL_FALSE;
2142 					return 1;
2143 				}
2144 
2145 				if (Z_REFCOUNT_P(ch->clone) <= 1) {
2146 					zend_llist_clean(&ch->to_free->post);
2147 				}
2148 				zend_llist_add_element(&ch->to_free->post, &first);
2149 				error = curl_easy_setopt(ch->cp, CURLOPT_HTTPPOST, first);
2150 
2151 			} else {
2152 #if LIBCURL_VERSION_NUM >= 0x071101
2153 				convert_to_string_ex(zvalue);
2154 				/* with curl 7.17.0 and later, we can use COPYPOSTFIELDS, but we have to provide size before */
2155 				error = curl_easy_setopt(ch->cp, CURLOPT_POSTFIELDSIZE, Z_STRLEN_PP(zvalue));
2156 				error = curl_easy_setopt(ch->cp, CURLOPT_COPYPOSTFIELDS, Z_STRVAL_PP(zvalue));
2157 #else
2158 				char *post = NULL;
2159 
2160 				convert_to_string_ex(zvalue);
2161 				post = estrndup(Z_STRVAL_PP(zvalue), Z_STRLEN_PP(zvalue));
2162 				zend_llist_add_element(&ch->to_free->str, &post);
2163 
2164 				error = curl_easy_setopt(ch->cp, CURLOPT_POSTFIELDS, post);
2165 				error = curl_easy_setopt(ch->cp, CURLOPT_POSTFIELDSIZE, Z_STRLEN_PP(zvalue));
2166 #endif
2167 			}
2168 			break;
2169 		case CURLOPT_HTTPHEADER:
2170 		case CURLOPT_QUOTE:
2171 		case CURLOPT_HTTP200ALIASES:
2172 		case CURLOPT_POSTQUOTE: {
2173 			zval              **current;
2174 			HashTable          *ph;
2175 			struct curl_slist  *slist = NULL;
2176 
2177 			ph = HASH_OF(*zvalue);
2178 			if (!ph) {
2179 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "You must pass either an object or an array with the CURLOPT_HTTPHEADER, CURLOPT_QUOTE, CURLOPT_HTTP200ALIASES and CURLOPT_POSTQUOTE arguments");
2180 				RETVAL_FALSE;
2181 				return 1;
2182 			}
2183 
2184 			for (zend_hash_internal_pointer_reset(ph);
2185 				 zend_hash_get_current_data(ph, (void **) &current) == SUCCESS;
2186 				 zend_hash_move_forward(ph)
2187 			) {
2188 				SEPARATE_ZVAL(current);
2189 				convert_to_string_ex(current);
2190 
2191 				slist = curl_slist_append(slist, Z_STRVAL_PP(current));
2192 				if (!slist) {
2193 					php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not build curl_slist");
2194 					RETVAL_FALSE;
2195 					return 1;
2196 				}
2197 			}
2198 			zend_hash_index_update(ch->to_free->slist, (ulong) option, &slist, sizeof(struct curl_slist *), NULL);
2199 
2200 			error = curl_easy_setopt(ch->cp, option, slist);
2201 
2202 			break;
2203 		}
2204 		/* the following options deal with files, therefore the open_basedir check
2205 		 * is required.
2206 		 */
2207 		case CURLOPT_COOKIEJAR:
2208 		case CURLOPT_SSLCERT:
2209 		case CURLOPT_RANDOM_FILE:
2210 		case CURLOPT_COOKIEFILE: {
2211 #if LIBCURL_VERSION_NUM < 0x071100
2212 			char *copystr = NULL;
2213 #endif
2214 
2215 			convert_to_string_ex(zvalue);
2216 
2217 			if (Z_STRLEN_PP(zvalue) && php_check_open_basedir(Z_STRVAL_PP(zvalue) TSRMLS_CC)) {
2218 				RETVAL_FALSE;
2219 				return 1;
2220 			}
2221 
2222 #if LIBCURL_VERSION_NUM >= 0x071100
2223 			error = curl_easy_setopt(ch->cp, option, Z_STRVAL_PP(zvalue));
2224 #else
2225 			copystr = estrndup(Z_STRVAL_PP(zvalue), Z_STRLEN_PP(zvalue));
2226 
2227 			error = curl_easy_setopt(ch->cp, option, copystr);
2228 			zend_llist_add_element(&ch->to_free->str, &copystr);
2229 #endif
2230 			break;
2231 		}
2232 		case CURLINFO_HEADER_OUT:
2233 			convert_to_long_ex(zvalue);
2234 			if (Z_LVAL_PP(zvalue) == 1) {
2235 				curl_easy_setopt(ch->cp, CURLOPT_DEBUGFUNCTION, curl_debug);
2236 				curl_easy_setopt(ch->cp, CURLOPT_DEBUGDATA, (void *)ch);
2237 				curl_easy_setopt(ch->cp, CURLOPT_VERBOSE, 1);
2238 			} else {
2239 				curl_easy_setopt(ch->cp, CURLOPT_DEBUGFUNCTION, NULL);
2240 				curl_easy_setopt(ch->cp, CURLOPT_DEBUGDATA, NULL);
2241 				curl_easy_setopt(ch->cp, CURLOPT_VERBOSE, 0);
2242 			}
2243 			break;
2244 	}
2245 
2246 	SAVE_CURL_ERROR(ch, error);
2247 	if (error != CURLE_OK) {
2248 		return 1;
2249 	} else {
2250 		return 0;
2251 	}
2252 }
2253 /* }}} */
2254 
2255 /* {{{ proto bool curl_setopt(resource ch, int option, mixed value)
2256    Set an option for a cURL transfer */
PHP_FUNCTION(curl_setopt)2257 PHP_FUNCTION(curl_setopt)
2258 {
2259 	zval       *zid, **zvalue;
2260 	long        options;
2261 	php_curl   *ch;
2262 
2263 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlZ", &zid, &options, &zvalue) == FAILURE) {
2264 		return;
2265 	}
2266 
2267 	ZEND_FETCH_RESOURCE(ch, php_curl *, &zid, -1, le_curl_name, le_curl);
2268 
2269 	if (options <= 0) {
2270 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid curl configuration option");
2271 		RETURN_FALSE;
2272 	}
2273 
2274 	if (!_php_curl_setopt(ch, options, zvalue, return_value TSRMLS_CC)) {
2275 		RETURN_TRUE;
2276 	} else {
2277 		RETURN_FALSE;
2278 	}
2279 }
2280 /* }}} */
2281 
2282 /* {{{ proto bool curl_setopt_array(resource ch, array options)
2283    Set an array of option for a cURL transfer */
PHP_FUNCTION(curl_setopt_array)2284 PHP_FUNCTION(curl_setopt_array)
2285 {
2286 	zval		*zid, *arr, **entry;
2287 	php_curl	*ch;
2288 	ulong		option;
2289 	HashPosition	pos;
2290 	char		*string_key;
2291 	uint		str_key_len;
2292 
2293 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "za", &zid, &arr) == FAILURE) {
2294 		return;
2295 	}
2296 
2297 	ZEND_FETCH_RESOURCE(ch, php_curl *, &zid, -1, le_curl_name, le_curl);
2298 
2299 	zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(arr), &pos);
2300 	while (zend_hash_get_current_data_ex(Z_ARRVAL_P(arr), (void **)&entry, &pos) == SUCCESS) {
2301 		if (zend_hash_get_current_key_ex(Z_ARRVAL_P(arr), &string_key, &str_key_len, &option, 0, &pos) != HASH_KEY_IS_LONG) {
2302 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Array keys must be CURLOPT constants or equivalent integer values");
2303 			RETURN_FALSE;
2304 		}
2305 		if (_php_curl_setopt(ch, (long) option, entry, return_value TSRMLS_CC)) {
2306 			RETURN_FALSE;
2307 		}
2308 		zend_hash_move_forward_ex(Z_ARRVAL_P(arr), &pos);
2309 	}
2310 	RETURN_TRUE;
2311 }
2312 /* }}} */
2313 
2314 /* {{{ _php_curl_cleanup_handle(ch)
2315    Cleanup an execution phase */
_php_curl_cleanup_handle(php_curl * ch)2316 void _php_curl_cleanup_handle(php_curl *ch)
2317 {
2318 	if (ch->handlers->write->buf.len > 0) {
2319 		smart_str_free(&ch->handlers->write->buf);
2320 	}
2321 	if (ch->header.str_len) {
2322 		efree(ch->header.str);
2323 		ch->header.str_len = 0;
2324 	}
2325 
2326 	memset(ch->err.str, 0, CURL_ERROR_SIZE + 1);
2327 	ch->err.no = 0;
2328 }
2329 /* }}} */
2330 
2331 /* {{{ proto bool curl_exec(resource ch)
2332    Perform a cURL session */
PHP_FUNCTION(curl_exec)2333 PHP_FUNCTION(curl_exec)
2334 {
2335 	CURLcode	error;
2336 	zval		*zid;
2337 	php_curl	*ch;
2338 
2339 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zid) == FAILURE) {
2340 		return;
2341 	}
2342 
2343 	ZEND_FETCH_RESOURCE(ch, php_curl *, &zid, -1, le_curl_name, le_curl);
2344 
2345 	_php_curl_verify_handlers(ch, 1 TSRMLS_CC);
2346 
2347 	_php_curl_cleanup_handle(ch);
2348 
2349 	error = curl_easy_perform(ch->cp);
2350 	SAVE_CURL_ERROR(ch, error);
2351 	/* CURLE_PARTIAL_FILE is returned by HEAD requests */
2352 	if (error != CURLE_OK && error != CURLE_PARTIAL_FILE) {
2353 		if (ch->handlers->write->buf.len > 0) {
2354 			smart_str_free(&ch->handlers->write->buf);
2355 		}
2356 		RETURN_FALSE;
2357 	}
2358 
2359 	if (ch->handlers->std_err) {
2360 		php_stream  *stream;
2361 		stream = (php_stream*)zend_fetch_resource(&ch->handlers->std_err TSRMLS_CC, -1, NULL, NULL, 2, php_file_le_stream(), php_file_le_pstream());
2362 		if (stream) {
2363 			php_stream_flush(stream);
2364 		}
2365 	}
2366 
2367 	if (ch->handlers->write->method == PHP_CURL_RETURN && ch->handlers->write->buf.len > 0) {
2368 		smart_str_0(&ch->handlers->write->buf);
2369 		RETURN_STRINGL(ch->handlers->write->buf.c, ch->handlers->write->buf.len, 1);
2370 	}
2371 
2372 	/* flush the file handle, so any remaining data is synched to disk */
2373 	if (ch->handlers->write->method == PHP_CURL_FILE && ch->handlers->write->fp) {
2374 		fflush(ch->handlers->write->fp);
2375 	}
2376 	if (ch->handlers->write_header->method == PHP_CURL_FILE && ch->handlers->write_header->fp) {
2377 		fflush(ch->handlers->write_header->fp);
2378 	}
2379 
2380 	if (ch->handlers->write->method == PHP_CURL_RETURN) {
2381 		RETURN_EMPTY_STRING();
2382 	} else {
2383 		RETURN_TRUE;
2384 	}
2385 }
2386 /* }}} */
2387 
2388 /* {{{ proto mixed curl_getinfo(resource ch [, int option])
2389    Get information regarding a specific transfer */
PHP_FUNCTION(curl_getinfo)2390 PHP_FUNCTION(curl_getinfo)
2391 {
2392 	zval		*zid;
2393 	php_curl	*ch;
2394 	long		option = 0;
2395 
2396 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &zid, &option) == FAILURE) {
2397 		return;
2398 	}
2399 
2400 	ZEND_FETCH_RESOURCE(ch, php_curl *, &zid, -1, le_curl_name, le_curl);
2401 
2402 	if (ZEND_NUM_ARGS() < 2) {
2403 		char   *s_code;
2404 		long    l_code;
2405 		double  d_code;
2406 #if LIBCURL_VERSION_NUM >  0x071301
2407 		struct curl_certinfo *ci = NULL;
2408 		zval *listcode;
2409 #endif
2410 
2411 		array_init(return_value);
2412 
2413 		if (curl_easy_getinfo(ch->cp, CURLINFO_EFFECTIVE_URL, &s_code) == CURLE_OK) {
2414 			CAAS("url", s_code);
2415 		}
2416 		if (curl_easy_getinfo(ch->cp, CURLINFO_CONTENT_TYPE, &s_code) == CURLE_OK) {
2417 			if (s_code != NULL) {
2418 				CAAS("content_type", s_code);
2419 			} else {
2420 				zval *retnull;
2421 				MAKE_STD_ZVAL(retnull);
2422 				ZVAL_NULL(retnull);
2423 				CAAZ("content_type", retnull);
2424 			}
2425 		}
2426 		if (curl_easy_getinfo(ch->cp, CURLINFO_HTTP_CODE, &l_code) == CURLE_OK) {
2427 			CAAL("http_code", l_code);
2428 		}
2429 		if (curl_easy_getinfo(ch->cp, CURLINFO_HEADER_SIZE, &l_code) == CURLE_OK) {
2430 			CAAL("header_size", l_code);
2431 		}
2432 		if (curl_easy_getinfo(ch->cp, CURLINFO_REQUEST_SIZE, &l_code) == CURLE_OK) {
2433 			CAAL("request_size", l_code);
2434 		}
2435 		if (curl_easy_getinfo(ch->cp, CURLINFO_FILETIME, &l_code) == CURLE_OK) {
2436 			CAAL("filetime", l_code);
2437 		}
2438 		if (curl_easy_getinfo(ch->cp, CURLINFO_SSL_VERIFYRESULT, &l_code) == CURLE_OK) {
2439 			CAAL("ssl_verify_result", l_code);
2440 		}
2441 		if (curl_easy_getinfo(ch->cp, CURLINFO_REDIRECT_COUNT, &l_code) == CURLE_OK) {
2442 			CAAL("redirect_count", l_code);
2443 		}
2444 		if (curl_easy_getinfo(ch->cp, CURLINFO_TOTAL_TIME, &d_code) == CURLE_OK) {
2445 			CAAD("total_time", d_code);
2446 		}
2447 		if (curl_easy_getinfo(ch->cp, CURLINFO_NAMELOOKUP_TIME, &d_code) == CURLE_OK) {
2448 			CAAD("namelookup_time", d_code);
2449 		}
2450 		if (curl_easy_getinfo(ch->cp, CURLINFO_CONNECT_TIME, &d_code) == CURLE_OK) {
2451 			CAAD("connect_time", d_code);
2452 		}
2453 		if (curl_easy_getinfo(ch->cp, CURLINFO_PRETRANSFER_TIME, &d_code) == CURLE_OK) {
2454 			CAAD("pretransfer_time", d_code);
2455 		}
2456 		if (curl_easy_getinfo(ch->cp, CURLINFO_SIZE_UPLOAD, &d_code) == CURLE_OK) {
2457 			CAAD("size_upload", d_code);
2458 		}
2459 		if (curl_easy_getinfo(ch->cp, CURLINFO_SIZE_DOWNLOAD, &d_code) == CURLE_OK) {
2460 			CAAD("size_download", d_code);
2461 		}
2462 		if (curl_easy_getinfo(ch->cp, CURLINFO_SPEED_DOWNLOAD, &d_code) == CURLE_OK) {
2463 			CAAD("speed_download", d_code);
2464 		}
2465 		if (curl_easy_getinfo(ch->cp, CURLINFO_SPEED_UPLOAD, &d_code) == CURLE_OK) {
2466 			CAAD("speed_upload", d_code);
2467 		}
2468 		if (curl_easy_getinfo(ch->cp, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d_code) == CURLE_OK) {
2469 			CAAD("download_content_length", d_code);
2470 		}
2471 		if (curl_easy_getinfo(ch->cp, CURLINFO_CONTENT_LENGTH_UPLOAD, &d_code) == CURLE_OK) {
2472 			CAAD("upload_content_length", d_code);
2473 		}
2474 		if (curl_easy_getinfo(ch->cp, CURLINFO_STARTTRANSFER_TIME, &d_code) == CURLE_OK) {
2475 			CAAD("starttransfer_time", d_code);
2476 		}
2477 		if (curl_easy_getinfo(ch->cp, CURLINFO_REDIRECT_TIME, &d_code) == CURLE_OK) {
2478 			CAAD("redirect_time", d_code);
2479 		}
2480 #if LIBCURL_VERSION_NUM > 0x071301
2481 		if (curl_easy_getinfo(ch->cp, CURLINFO_CERTINFO, &ci) == CURLE_OK) {
2482 			MAKE_STD_ZVAL(listcode);
2483 			array_init(listcode);
2484 			create_certinfo(ci, listcode TSRMLS_CC);
2485 			CAAZ("certinfo", listcode);
2486 		}
2487 #endif
2488 #if LIBCURL_VERSION_NUM >= 0x071300 /* 7.19.0 */
2489 		if (curl_easy_getinfo(ch->cp, CURLINFO_PRIMARY_IP, &s_code) == CURLE_OK) {
2490 			CAAS("primary_ip", s_code);
2491 		}
2492 #endif
2493 #if LIBCURL_VERSION_NUM > 0x071500
2494 		if (curl_easy_getinfo(ch->cp, CURLINFO_PRIMARY_PORT, &l_code) == CURLE_OK) {
2495 			CAAL("primary_port", l_code);
2496 		}
2497 		if (curl_easy_getinfo(ch->cp, CURLINFO_LOCAL_IP, &s_code) == CURLE_OK) {
2498 			CAAS("local_ip", s_code);
2499 		}
2500 		if (curl_easy_getinfo(ch->cp, CURLINFO_LOCAL_PORT, &l_code) == CURLE_OK) {
2501 			CAAL("local_port", l_code);
2502 		}
2503 #endif
2504 #if LIBCURL_VERSION_NUM >= 0x071202
2505 		if (curl_easy_getinfo(ch->cp, CURLINFO_REDIRECT_URL, &s_code) == CURLE_OK) {
2506 			CAAS("redirect_url", s_code);
2507 		}
2508 #endif
2509 		if (ch->header.str_len > 0) {
2510 			CAAS("request_header", ch->header.str);
2511 		}
2512 	} else {
2513 		switch (option) {
2514 			/* string variable types */
2515 #if LIBCURL_VERSION_NUM >= 0x071300 /* 7.19.0 */
2516 			case CURLINFO_PRIMARY_IP:
2517 #endif
2518 #if LIBCURL_VERSION_NUM >= 0x071500 /* 7.21.0 */
2519 			case CURLINFO_LOCAL_IP:
2520 #endif
2521 			case CURLINFO_PRIVATE:
2522 			case CURLINFO_EFFECTIVE_URL:
2523 			case CURLINFO_CONTENT_TYPE:
2524 #if LIBCURL_VERSION_NUM >= 0x071202
2525 			case CURLINFO_REDIRECT_URL:
2526 #endif
2527 			{
2528 				char *s_code = NULL;
2529 
2530 				if (curl_easy_getinfo(ch->cp, option, &s_code) == CURLE_OK && s_code) {
2531 					RETURN_STRING(s_code, 1);
2532 				} else {
2533 					RETURN_FALSE;
2534 				}
2535 				break;
2536 			}
2537 			/* Long variable types */
2538 #if LIBCURL_VERSION_NUM >= 0x071500 /* 7.21.0 */
2539 			case CURLINFO_PRIMARY_PORT:
2540 			case CURLINFO_LOCAL_PORT:
2541 #endif
2542 			case CURLINFO_HTTP_CODE:
2543 			case CURLINFO_HEADER_SIZE:
2544 			case CURLINFO_REQUEST_SIZE:
2545 			case CURLINFO_FILETIME:
2546 			case CURLINFO_SSL_VERIFYRESULT:
2547 			case CURLINFO_REDIRECT_COUNT: {
2548 				long code = 0;
2549 
2550 				if (curl_easy_getinfo(ch->cp, option, &code) == CURLE_OK) {
2551 					RETURN_LONG(code);
2552 				} else {
2553 					RETURN_FALSE;
2554 				}
2555 				break;
2556 			}
2557 			/* Double variable types */
2558 			case CURLINFO_TOTAL_TIME:
2559 			case CURLINFO_NAMELOOKUP_TIME:
2560 			case CURLINFO_CONNECT_TIME:
2561 			case CURLINFO_PRETRANSFER_TIME:
2562 			case CURLINFO_SIZE_UPLOAD:
2563 			case CURLINFO_SIZE_DOWNLOAD:
2564 			case CURLINFO_SPEED_DOWNLOAD:
2565 			case CURLINFO_SPEED_UPLOAD:
2566 			case CURLINFO_CONTENT_LENGTH_DOWNLOAD:
2567 			case CURLINFO_CONTENT_LENGTH_UPLOAD:
2568 			case CURLINFO_STARTTRANSFER_TIME:
2569 			case CURLINFO_REDIRECT_TIME: {
2570 				double code = 0.0;
2571 
2572 				if (curl_easy_getinfo(ch->cp, option, &code) == CURLE_OK) {
2573 					RETURN_DOUBLE(code);
2574 				} else {
2575 					RETURN_FALSE;
2576 				}
2577 				break;
2578 			}
2579 			case CURLINFO_HEADER_OUT:
2580 				if (ch->header.str_len > 0) {
2581 					RETURN_STRINGL(ch->header.str, ch->header.str_len, 1);
2582 				} else {
2583 					RETURN_FALSE;
2584 				}
2585 #if LIBCURL_VERSION_NUM > 0x071301
2586 			case CURLINFO_CERTINFO: {
2587 				struct curl_certinfo *ci = NULL;
2588 
2589 				array_init(return_value);
2590 
2591 				if (curl_easy_getinfo(ch->cp, CURLINFO_CERTINFO, &ci) == CURLE_OK) {
2592 					create_certinfo(ci, return_value TSRMLS_CC);
2593 				} else {
2594 					RETURN_FALSE;
2595 				}
2596 				break;
2597 			}
2598 #endif
2599 		}
2600 	}
2601 }
2602 /* }}} */
2603 
2604 /* {{{ proto string curl_error(resource ch)
2605    Return a string contain the last error for the current session */
PHP_FUNCTION(curl_error)2606 PHP_FUNCTION(curl_error)
2607 {
2608 	zval		*zid;
2609 	php_curl	*ch;
2610 
2611 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zid) == FAILURE) {
2612 		return;
2613 	}
2614 
2615 	ZEND_FETCH_RESOURCE(ch, php_curl *, &zid, -1, le_curl_name, le_curl);
2616 
2617 	ch->err.str[CURL_ERROR_SIZE] = 0;
2618 	RETURN_STRING(ch->err.str, 1);
2619 }
2620 /* }}} */
2621 
2622 /* {{{ proto int curl_errno(resource ch)
2623    Return an integer containing the last error number */
PHP_FUNCTION(curl_errno)2624 PHP_FUNCTION(curl_errno)
2625 {
2626 	zval		*zid;
2627 	php_curl	*ch;
2628 
2629 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zid) == FAILURE) {
2630 		return;
2631 	}
2632 
2633 	ZEND_FETCH_RESOURCE(ch, php_curl *, &zid, -1, le_curl_name, le_curl);
2634 
2635 	RETURN_LONG(ch->err.no);
2636 }
2637 /* }}} */
2638 
2639 /* {{{ proto void curl_close(resource ch)
2640    Close a cURL session */
PHP_FUNCTION(curl_close)2641 PHP_FUNCTION(curl_close)
2642 {
2643 	zval		*zid;
2644 	php_curl	*ch;
2645 
2646 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zid) == FAILURE) {
2647 		return;
2648 	}
2649 
2650 	ZEND_FETCH_RESOURCE(ch, php_curl *, &zid, -1, le_curl_name, le_curl);
2651 
2652 	if (ch->in_callback) {
2653 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attempt to close cURL handle from a callback");
2654 		return;
2655 	}
2656 
2657 	if (ch->uses) {
2658 		ch->uses--;
2659 	} else {
2660 		zend_list_delete(Z_LVAL_P(zid));
2661 	}
2662 }
2663 /* }}} */
2664 
2665 /* {{{ _php_curl_close()
2666    List destructor for curl handles */
_php_curl_close_ex(php_curl * ch TSRMLS_DC)2667 static void _php_curl_close_ex(php_curl *ch TSRMLS_DC)
2668 {
2669 #if PHP_CURL_DEBUG
2670 	fprintf(stderr, "DTOR CALLED, ch = %x\n", ch);
2671 #endif
2672 
2673 	_php_curl_verify_handlers(ch, 0 TSRMLS_CC);
2674 
2675 	/*
2676 	 * Libcurl is doing connection caching. When easy handle is cleaned up,
2677 	 * if the handle was previously used by the curl_multi_api, the connection
2678 	 * remains open un the curl multi handle is cleaned up. Some protocols are
2679 	 * sending content like the FTP one, and libcurl try to use the
2680 	 * WRITEFUNCTION or the HEADERFUNCTION. Since structures used in those
2681 	 * callback are freed, we need to use an other callback to which avoid
2682 	 * segfaults.
2683 	 *
2684 	 * Libcurl commit d021f2e8a00 fix this issue and should be part of 7.28.2
2685 	 */
2686 	curl_easy_setopt(ch->cp, CURLOPT_HEADERFUNCTION, curl_write_nothing);
2687 	curl_easy_setopt(ch->cp, CURLOPT_WRITEFUNCTION, curl_write_nothing);
2688 
2689 	curl_easy_cleanup(ch->cp);
2690 
2691 	/* cURL destructors should be invoked only by last curl handle */
2692 	if (Z_REFCOUNT_P(ch->clone) <= 1) {
2693 		zend_llist_clean(&ch->to_free->str);
2694 		zend_llist_clean(&ch->to_free->post);
2695 		zend_hash_destroy(ch->to_free->slist);
2696 		efree(ch->to_free->slist);
2697 		efree(ch->to_free);
2698 		FREE_ZVAL(ch->clone);
2699 	} else {
2700 		Z_DELREF_P(ch->clone);
2701 	}
2702 
2703 	if (ch->handlers->write->buf.len > 0) {
2704 		smart_str_free(&ch->handlers->write->buf);
2705 	}
2706 	if (ch->handlers->write->func_name) {
2707 		zval_ptr_dtor(&ch->handlers->write->func_name);
2708 	}
2709 	if (ch->handlers->read->func_name) {
2710 		zval_ptr_dtor(&ch->handlers->read->func_name);
2711 	}
2712 	if (ch->handlers->write_header->func_name) {
2713 		zval_ptr_dtor(&ch->handlers->write_header->func_name);
2714 	}
2715 	if (ch->handlers->progress->func_name) {
2716 		zval_ptr_dtor(&ch->handlers->progress->func_name);
2717 	}
2718 	if (ch->handlers->passwd) {
2719 		zval_ptr_dtor(&ch->handlers->passwd);
2720 	}
2721 	if (ch->handlers->std_err) {
2722 		zval_ptr_dtor(&ch->handlers->std_err);
2723 	}
2724 	if (ch->header.str_len > 0) {
2725 		efree(ch->header.str);
2726 	}
2727 
2728 	if (ch->handlers->write_header->stream) {
2729 		zval_ptr_dtor(&ch->handlers->write_header->stream);
2730 	}
2731 	if (ch->handlers->write->stream) {
2732 		zval_ptr_dtor(&ch->handlers->write->stream);
2733 	}
2734 	if (ch->handlers->read->stream) {
2735 		zval_ptr_dtor(&ch->handlers->read->stream);
2736 	}
2737 
2738 	efree(ch->handlers->write);
2739 	efree(ch->handlers->write_header);
2740 	efree(ch->handlers->read);
2741 	efree(ch->handlers->progress);
2742 	efree(ch->handlers);
2743 	efree(ch);
2744 }
2745 /* }}} */
2746 
2747 /* {{{ _php_curl_close()
2748    List destructor for curl handles */
_php_curl_close(zend_rsrc_list_entry * rsrc TSRMLS_DC)2749 static void _php_curl_close(zend_rsrc_list_entry *rsrc TSRMLS_DC)
2750 {
2751 	php_curl *ch = (php_curl *) rsrc->ptr;
2752 	_php_curl_close_ex(ch TSRMLS_CC);
2753 }
2754 /* }}} */
2755 
2756 #endif /* HAVE_CURL */
2757 
2758 /*
2759  * Local variables:
2760  * tab-width: 4
2761  * c-basic-offset: 4
2762  * End:
2763  * vim600: fdm=marker
2764  * vim: noet sw=4 ts=4
2765  */
2766