xref: /PHP-7.2/ext/curl/multi.c (revision c8c183eb)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 7                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2018 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 "php_curl.h"
32 
33 #include <curl/curl.h>
34 #include <curl/multi.h>
35 
36 #ifdef HAVE_SYS_SELECT_H
37 #include <sys/select.h>
38 #endif
39 
40 #ifdef HAVE_SYS_TIME_H
41 #include <sys/time.h>
42 #endif
43 
44 #ifdef HAVE_SYS_TYPES_H
45 #include <sys/types.h>
46 #endif
47 
48 #ifdef HAVE_UNISTD_H
49 #include <unistd.h>
50 #endif
51 
52 #define SAVE_CURLM_ERROR(__handle, __err) (__handle)->err.no = (int) __err;
53 
54 /* {{{ proto resource curl_multi_init(void)
55    Returns a new cURL multi handle */
PHP_FUNCTION(curl_multi_init)56 PHP_FUNCTION(curl_multi_init)
57 {
58 	php_curlm *mh;
59 
60 	if (zend_parse_parameters_none() == FAILURE) {
61 		return;
62 	}
63 
64 	mh = ecalloc(1, sizeof(php_curlm));
65 	mh->multi = curl_multi_init();
66 	mh->handlers = ecalloc(1, sizeof(php_curlm_handlers));
67 
68 	zend_llist_init(&mh->easyh, sizeof(zval), _php_curl_multi_cleanup_list, 0);
69 
70 	RETURN_RES(zend_register_resource(mh, le_curl_multi_handle));
71 }
72 /* }}} */
73 
74 /* {{{ proto int curl_multi_add_handle(resource mh, resource ch)
75    Add a normal cURL handle to a cURL multi handle */
PHP_FUNCTION(curl_multi_add_handle)76 PHP_FUNCTION(curl_multi_add_handle)
77 {
78 	zval      *z_mh;
79 	zval      *z_ch;
80 	php_curlm *mh;
81 	php_curl  *ch;
82 	zval tmp_val;
83 	CURLMcode error = CURLM_OK;
84 
85 	ZEND_PARSE_PARAMETERS_START(2,2)
86 		Z_PARAM_RESOURCE(z_mh)
87 		Z_PARAM_RESOURCE(z_ch)
88 	ZEND_PARSE_PARAMETERS_END();
89 
90 	if ((mh = (php_curlm *)zend_fetch_resource(Z_RES_P(z_mh), le_curl_multi_handle_name, le_curl_multi_handle)) == NULL) {
91 		RETURN_FALSE;
92 	}
93 
94 	if ((ch = (php_curl *)zend_fetch_resource(Z_RES_P(z_ch), le_curl_name, le_curl)) == NULL) {
95 		RETURN_FALSE;
96 	}
97 
98 	_php_curl_cleanup_handle(ch);
99 
100 	/* we want to create a copy of this zval that we store in the multihandle structure element "easyh" */
101 	ZVAL_DUP(&tmp_val, z_ch);
102 
103 	zend_llist_add_element(&mh->easyh, &tmp_val);
104 
105 	error = curl_multi_add_handle(mh->multi, ch->cp);
106 	SAVE_CURLM_ERROR(mh, error);
107 
108 	RETURN_LONG((zend_long) error);
109 }
110 /* }}} */
111 
_php_curl_multi_cleanup_list(void * data)112 void _php_curl_multi_cleanup_list(void *data) /* {{{ */
113 {
114 	zval *z_ch = (zval *)data;
115 	php_curl *ch;
116 
117 	if (!z_ch) {
118 		return;
119 	}
120 	if (!Z_RES_P(z_ch)->ptr) {
121 		return;
122 	}
123 	if ((ch = (php_curl *)zend_fetch_resource(Z_RES_P(z_ch), le_curl_name, le_curl)) == NULL) {
124 		return;
125 	}
126 
127 	zend_list_delete(Z_RES_P(z_ch));
128 }
129 /* }}} */
130 
131 /* Used internally as comparison routine passed to zend_list_del_element */
curl_compare_resources(zval * z1,zval * z2)132 static int curl_compare_resources( zval *z1, zval *z2 ) /* {{{ */
133 {
134 	return (Z_TYPE_P(z1) == Z_TYPE_P(z2) &&
135 			Z_TYPE_P(z1) == IS_RESOURCE &&
136 			Z_RES_P(z1) == Z_RES_P(z2));
137 }
138 /* }}} */
139 
140 /* Used to find the php_curl resource for a given curl easy handle */
_php_curl_multi_find_easy_handle(php_curlm * mh,CURL * easy)141 static zval *_php_curl_multi_find_easy_handle(php_curlm *mh, CURL *easy) /* {{{ */
142 {
143 	php_curl 			*tmp_ch;
144 	zend_llist_position pos;
145 	zval				*pz_ch_temp;
146 
147 	for(pz_ch_temp = (zval *)zend_llist_get_first_ex(&mh->easyh, &pos); pz_ch_temp;
148 		pz_ch_temp = (zval *)zend_llist_get_next_ex(&mh->easyh, &pos)) {
149 
150 		if ((tmp_ch = (php_curl *)zend_fetch_resource(Z_RES_P(pz_ch_temp), le_curl_name, le_curl)) == NULL) {
151 			return NULL;
152 		}
153 
154 		if (tmp_ch->cp == easy) {
155 			return pz_ch_temp;
156 		}
157 	}
158 
159 	return NULL;
160 }
161 /* }}} */
162 
163 /* {{{ proto int curl_multi_remove_handle(resource mh, resource ch)
164    Remove a multi handle from a set of cURL handles */
PHP_FUNCTION(curl_multi_remove_handle)165 PHP_FUNCTION(curl_multi_remove_handle)
166 {
167 	zval      *z_mh;
168 	zval      *z_ch;
169 	php_curlm *mh;
170 	php_curl  *ch;
171 	CURLMcode error = CURLM_OK;
172 
173 	ZEND_PARSE_PARAMETERS_START(2,2)
174 		Z_PARAM_RESOURCE(z_mh)
175 		Z_PARAM_RESOURCE(z_ch)
176 	ZEND_PARSE_PARAMETERS_END();
177 
178 	if ((mh = (php_curlm *)zend_fetch_resource(Z_RES_P(z_mh), le_curl_multi_handle_name, le_curl_multi_handle)) == NULL) {
179 		RETURN_FALSE;
180 	}
181 
182 	if ((ch = (php_curl *)zend_fetch_resource(Z_RES_P(z_ch), le_curl_name, le_curl)) == NULL) {
183 		RETURN_FALSE;
184 	}
185 
186 	error = curl_multi_remove_handle(mh->multi, ch->cp);
187 	SAVE_CURLM_ERROR(mh, error);
188 
189 	RETVAL_LONG((zend_long) error);
190 	zend_llist_del_element(&mh->easyh, z_ch, (int (*)(void *, void *))curl_compare_resources);
191 
192 }
193 /* }}} */
194 
195 #if LIBCURL_VERSION_NUM < 0x071c00
_make_timeval_struct(struct timeval * to,double timeout)196 static void _make_timeval_struct(struct timeval *to, double timeout) /* {{{ */
197 {
198 	unsigned long conv;
199 
200 	conv = (unsigned long) (timeout * 1000000.0);
201 	to->tv_sec = conv / 1000000;
202 	to->tv_usec = conv % 1000000;
203 }
204 /* }}} */
205 #endif
206 
207 /* {{{ proto int curl_multi_select(resource mh[, double timeout])
208    Get all the sockets associated with the cURL extension, which can then be "selected" */
PHP_FUNCTION(curl_multi_select)209 PHP_FUNCTION(curl_multi_select)
210 {
211 	zval           *z_mh;
212 	php_curlm      *mh;
213 	double          timeout = 1.0;
214 #if LIBCURL_VERSION_NUM >= 0x071c00 /* Available since 7.28.0 */
215 	int             numfds = 0;
216 #else
217 	fd_set          readfds;
218 	fd_set          writefds;
219 	fd_set          exceptfds;
220 	int             maxfd;
221 	struct timeval  to;
222 #endif
223 	CURLMcode error = CURLM_OK;
224 
225 	ZEND_PARSE_PARAMETERS_START(1,2)
226 		Z_PARAM_RESOURCE(z_mh)
227 		Z_PARAM_OPTIONAL
228 		Z_PARAM_DOUBLE(timeout)
229 	ZEND_PARSE_PARAMETERS_END();
230 
231 	if ((mh = (php_curlm *)zend_fetch_resource(Z_RES_P(z_mh), le_curl_multi_handle_name, le_curl_multi_handle)) == NULL) {
232 		RETURN_FALSE;
233 	}
234 
235 #if LIBCURL_VERSION_NUM >= 0x071c00 /* Available since 7.28.0 */
236 	error = curl_multi_wait(mh->multi, NULL, 0, (unsigned long) (timeout * 1000.0), &numfds);
237 	if (CURLM_OK != error) {
238 		SAVE_CURLM_ERROR(mh, error);
239 		RETURN_LONG(-1);
240 	}
241 
242 	RETURN_LONG(numfds);
243 #else
244 	_make_timeval_struct(&to, timeout);
245 
246 	FD_ZERO(&readfds);
247 	FD_ZERO(&writefds);
248 	FD_ZERO(&exceptfds);
249 
250 	error = curl_multi_fdset(mh->multi, &readfds, &writefds, &exceptfds, &maxfd);
251 	SAVE_CURLM_ERROR(mh, error);
252 
253 	if (maxfd == -1) {
254 		RETURN_LONG(-1);
255 	}
256 	RETURN_LONG(select(maxfd + 1, &readfds, &writefds, &exceptfds, &to));
257 #endif
258 }
259 /* }}} */
260 
261 /* {{{ proto int curl_multi_exec(resource mh, int &still_running)
262    Run the sub-connections of the current cURL handle */
PHP_FUNCTION(curl_multi_exec)263 PHP_FUNCTION(curl_multi_exec)
264 {
265 	zval      *z_mh;
266 	zval      *z_still_running;
267 	php_curlm *mh;
268 	int        still_running;
269 	CURLMcode error = CURLM_OK;
270 
271 	ZEND_PARSE_PARAMETERS_START(2, 2)
272 		Z_PARAM_RESOURCE(z_mh)
273 		Z_PARAM_ZVAL_DEREF(z_still_running)
274 	ZEND_PARSE_PARAMETERS_END();
275 
276 	if ((mh = (php_curlm *)zend_fetch_resource(Z_RES_P(z_mh), le_curl_multi_handle_name, le_curl_multi_handle)) == NULL) {
277 		RETURN_FALSE;
278 	}
279 
280 	{
281 		zend_llist_position pos;
282 		php_curl *ch;
283 		zval	*pz_ch;
284 
285 		for (pz_ch = (zval *)zend_llist_get_first_ex(&mh->easyh, &pos); pz_ch;
286 			pz_ch = (zval *)zend_llist_get_next_ex(&mh->easyh, &pos)) {
287 
288 			if ((ch = (php_curl *)zend_fetch_resource(Z_RES_P(pz_ch), le_curl_name, le_curl)) == NULL) {
289 				RETURN_FALSE;
290 			}
291 
292 			_php_curl_verify_handlers(ch, 1);
293 		}
294 	}
295 
296 	still_running = zval_get_long(z_still_running);
297 	error = curl_multi_perform(mh->multi, &still_running);
298 	zval_ptr_dtor(z_still_running);
299 	ZVAL_LONG(z_still_running, still_running);
300 
301 	SAVE_CURLM_ERROR(mh, error);
302 	RETURN_LONG((zend_long) error);
303 }
304 /* }}} */
305 
306 /* {{{ proto string curl_multi_getcontent(resource ch)
307    Return the content of a cURL handle if CURLOPT_RETURNTRANSFER is set */
PHP_FUNCTION(curl_multi_getcontent)308 PHP_FUNCTION(curl_multi_getcontent)
309 {
310 	zval     *z_ch;
311 	php_curl *ch;
312 
313 	ZEND_PARSE_PARAMETERS_START(1,1)
314 		Z_PARAM_RESOURCE(z_ch)
315 	ZEND_PARSE_PARAMETERS_END();
316 
317 	if ((ch = (php_curl *)zend_fetch_resource(Z_RES_P(z_ch), le_curl_name, le_curl)) == NULL) {
318 		RETURN_FALSE;
319 	}
320 
321 	if (ch->handlers->write->method == PHP_CURL_RETURN) {
322 		if (!ch->handlers->write->buf.s) {
323 			RETURN_EMPTY_STRING();
324 		}
325 		smart_str_0(&ch->handlers->write->buf);
326 		RETURN_STR_COPY(ch->handlers->write->buf.s);
327 	}
328 
329 	RETURN_NULL();
330 }
331 /* }}} */
332 
333 /* {{{ proto array curl_multi_info_read(resource mh [, long &msgs_in_queue])
334    Get information about the current transfers */
PHP_FUNCTION(curl_multi_info_read)335 PHP_FUNCTION(curl_multi_info_read)
336 {
337 	zval      *z_mh;
338 	php_curlm *mh;
339 	CURLMsg	  *tmp_msg;
340 	int        queued_msgs;
341 	zval      *zmsgs_in_queue = NULL;
342 	php_curl  *ch;
343 
344 	ZEND_PARSE_PARAMETERS_START(1, 2)
345 		Z_PARAM_RESOURCE(z_mh)
346 		Z_PARAM_OPTIONAL
347 		Z_PARAM_ZVAL_DEREF(zmsgs_in_queue)
348 	ZEND_PARSE_PARAMETERS_END();
349 
350 	if ((mh = (php_curlm *)zend_fetch_resource(Z_RES_P(z_mh), le_curl_multi_handle_name, le_curl_multi_handle)) == NULL) {
351 		RETURN_FALSE;
352 	}
353 
354 	tmp_msg = curl_multi_info_read(mh->multi, &queued_msgs);
355 	if (tmp_msg == NULL) {
356 		RETURN_FALSE;
357 	}
358 	if (zmsgs_in_queue) {
359 		zval_ptr_dtor(zmsgs_in_queue);
360 		ZVAL_LONG(zmsgs_in_queue, queued_msgs);
361 	}
362 
363 	array_init(return_value);
364 	add_assoc_long(return_value, "msg", tmp_msg->msg);
365 	add_assoc_long(return_value, "result", tmp_msg->data.result);
366 
367 	/* find the original easy curl handle */
368 	{
369 		zval	*pz_ch = _php_curl_multi_find_easy_handle(mh, tmp_msg->easy_handle);
370 		if (pz_ch != NULL) {
371 			/* we are adding a reference to the underlying php_curl
372 			   resource, so we need to add one to the resource's refcount
373 			   in order to ensure it doesn't get destroyed when the
374 			   underlying curl easy handle goes out of scope.
375 			   Normally you would call zval_copy_ctor( pz_ch ), or
376 			   SEPARATE_ZVAL, but those create new zvals, which is already
377 			   being done in add_assoc_resource */
378 			Z_ADDREF_P(pz_ch);
379 
380 			/* we must save result to be able to read error message */
381 			ch = (php_curl*)zend_fetch_resource(Z_RES_P(pz_ch), le_curl_name, le_curl);
382 			SAVE_CURL_ERROR(ch, tmp_msg->data.result);
383 
384 			/* add_assoc_resource automatically creates a new zval to
385 			   wrap the "resource" represented by the current pz_ch */
386 
387 			add_assoc_zval(return_value, "handle", pz_ch);
388 		}
389 	}
390 }
391 /* }}} */
392 
393 /* {{{ proto void curl_multi_close(resource mh)
394    Close a set of cURL handles */
PHP_FUNCTION(curl_multi_close)395 PHP_FUNCTION(curl_multi_close)
396 {
397 	zval      *z_mh;
398 	php_curlm *mh;
399 
400 	ZEND_PARSE_PARAMETERS_START(1,1)
401 		Z_PARAM_RESOURCE(z_mh)
402 	ZEND_PARSE_PARAMETERS_END();
403 
404 	if ((mh = (php_curlm *)zend_fetch_resource(Z_RES_P(z_mh), le_curl_multi_handle_name, le_curl_multi_handle)) == NULL) {
405 		RETURN_FALSE;
406 	}
407 
408 	zend_list_close(Z_RES_P(z_mh));
409 }
410 /* }}} */
411 
_php_curl_multi_close(zend_resource * rsrc)412 void _php_curl_multi_close(zend_resource *rsrc) /* {{{ */
413 {
414 	php_curlm *mh = (php_curlm *)rsrc->ptr;
415 	if (mh) {
416 		zend_llist_position pos;
417 		php_curl *ch;
418 		zval	*pz_ch;
419 
420 		for (pz_ch = (zval *)zend_llist_get_first_ex(&mh->easyh, &pos); pz_ch;
421 			pz_ch = (zval *)zend_llist_get_next_ex(&mh->easyh, &pos)) {
422 			/* ptr is NULL means it already be freed */
423 			if (Z_RES_P(pz_ch)->ptr) {
424 				if ((ch = (php_curl *) zend_fetch_resource(Z_RES_P(pz_ch), le_curl_name, le_curl))) {
425 					_php_curl_verify_handlers(ch, 0);
426 				}
427 			}
428 		}
429 
430 		curl_multi_cleanup(mh->multi);
431 		zend_llist_clean(&mh->easyh);
432 		if (mh->handlers->server_push) {
433 			zval_ptr_dtor(&mh->handlers->server_push->func_name);
434 			efree(mh->handlers->server_push);
435 		}
436 		if (mh->handlers) {
437 			efree(mh->handlers);
438 		}
439 		efree(mh);
440 		rsrc->ptr = NULL;
441 	}
442 }
443 /* }}} */
444 
445 /* {{{ proto int curl_multi_errno(resource mh)
446          Return an integer containing the last multi curl error number */
PHP_FUNCTION(curl_multi_errno)447 PHP_FUNCTION(curl_multi_errno)
448 {
449 	zval        *z_mh;
450 	php_curlm   *mh;
451 
452 	ZEND_PARSE_PARAMETERS_START(1,1)
453 		Z_PARAM_RESOURCE(z_mh)
454 	ZEND_PARSE_PARAMETERS_END();
455 
456 	if ((mh = (php_curlm *)zend_fetch_resource(Z_RES_P(z_mh), le_curl_multi_handle_name, le_curl_multi_handle)) == NULL) {
457 		RETURN_FALSE;
458 	}
459 
460 	RETURN_LONG(mh->err.no);
461 }
462 /* }}} */
463 
464 #if LIBCURL_VERSION_NUM >= 0x070c00 /* Available since 7.12.0 */
465 /* {{{ proto bool curl_multi_strerror(int code)
466          return string describing error code */
PHP_FUNCTION(curl_multi_strerror)467 PHP_FUNCTION(curl_multi_strerror)
468 {
469 	zend_long code;
470 	const char *str;
471 
472 	ZEND_PARSE_PARAMETERS_START(1,1)
473 		Z_PARAM_LONG(code)
474 	ZEND_PARSE_PARAMETERS_END();
475 
476 	str = curl_multi_strerror(code);
477 	if (str) {
478 		RETURN_STRING(str);
479 	} else {
480 		RETURN_NULL();
481 	}
482 }
483 /* }}} */
484 #endif
485 
486 #if LIBCURL_VERSION_NUM >= 0x072C00 /* Available since 7.44.0 */
487 
_php_server_push_callback(CURL * parent_ch,CURL * easy,size_t num_headers,struct curl_pushheaders * push_headers,void * userp)488 static int _php_server_push_callback(CURL *parent_ch, CURL *easy, size_t num_headers, struct curl_pushheaders *push_headers, void *userp) /* {{{ */
489 {
490 	php_curl 				*ch;
491 	php_curl 				*parent;
492 	php_curlm 				*mh 			= (php_curlm *)userp;
493 	size_t 					rval 			= CURL_PUSH_DENY;
494 	php_curlm_server_push 	*t 				= mh->handlers->server_push;
495 	zval					*pz_parent_ch 	= NULL;
496 	zval 					pz_ch;
497 	zval 					headers;
498 	zval 					retval;
499 	zend_resource 			*res;
500 	char 					*header;
501 	int  					error;
502 	zend_fcall_info 		fci 			= empty_fcall_info;
503 
504 	pz_parent_ch = _php_curl_multi_find_easy_handle(mh, parent_ch);
505 	if (pz_parent_ch == NULL) {
506 		return rval;
507 	}
508 
509 	parent = (php_curl*)zend_fetch_resource(Z_RES_P(pz_parent_ch), le_curl_name, le_curl);
510 
511 	ch = alloc_curl_handle();
512 	ch->cp = easy;
513 	_php_setup_easy_copy_handlers(ch, parent);
514 
515 	Z_ADDREF_P(pz_parent_ch);
516 
517 	res = zend_register_resource(ch, le_curl);
518 	ch->res = res;
519 	ZVAL_RES(&pz_ch, res);
520 
521 	size_t i;
522 	array_init(&headers);
523 	for(i=0; i<num_headers; i++) {
524 		header = curl_pushheader_bynum(push_headers, i);
525 		add_next_index_string(&headers, header);
526   	}
527 
528 	zend_fcall_info_init(&t->func_name, 0, &fci, &t->fci_cache, NULL, NULL);
529 
530 	zend_fcall_info_argn(
531 		&fci, 3,
532 		pz_parent_ch,
533 		&pz_ch,
534 		&headers
535 	);
536 
537 	fci.retval = &retval;
538 
539 	error = zend_call_function(&fci, &t->fci_cache);
540 	zend_fcall_info_args_clear(&fci, 1);
541 	zval_dtor(&headers);
542 
543 	if (error == FAILURE) {
544 		php_error_docref(NULL, E_WARNING, "Cannot call the CURLMOPT_PUSHFUNCTION");
545 	} else if (!Z_ISUNDEF(retval)) {
546 		if (CURL_PUSH_DENY != zval_get_long(&retval)) {
547 		    rval = CURL_PUSH_OK;
548 
549 			/* we want to create a copy of this zval that we store in the multihandle structure element "easyh" */
550 			zval tmp_val;
551 			ZVAL_DUP(&tmp_val, &pz_ch);
552 			zend_llist_add_element(&mh->easyh, &tmp_val);
553 		} else {
554 			/* libcurl will free this easy handle, avoid double free */
555 			ch->cp = NULL;
556 		}
557 	}
558 
559 	return rval;
560 }
561 
562 #endif
563 
564 #if LIBCURL_VERSION_NUM >= 0x070f04 /* 7.15.4 */
_php_curl_multi_setopt(php_curlm * mh,zend_long option,zval * zvalue,zval * return_value)565 static int _php_curl_multi_setopt(php_curlm *mh, zend_long option, zval *zvalue, zval *return_value) /* {{{ */
566 {
567 	CURLMcode error = CURLM_OK;
568 
569 	switch (option) {
570 #if LIBCURL_VERSION_NUM >= 0x071000 /* 7.16.0 */
571 		case CURLMOPT_PIPELINING:
572 #endif
573 #if LIBCURL_VERSION_NUM >= 0x071003 /* 7.16.3 */
574 		case CURLMOPT_MAXCONNECTS:
575 #endif
576 #if LIBCURL_VERSION_NUM >= 0x071e00 /* 7.30.0 */
577 		case CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE:
578 		case CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE:
579 		case CURLMOPT_MAX_HOST_CONNECTIONS:
580 		case CURLMOPT_MAX_PIPELINE_LENGTH:
581 		case CURLMOPT_MAX_TOTAL_CONNECTIONS:
582 #endif
583 			error = curl_multi_setopt(mh->multi, option, zval_get_long(zvalue));
584 			break;
585 #if LIBCURL_VERSION_NUM > 0x072D00 /* Available since 7.46.0 */
586 		case CURLMOPT_PUSHFUNCTION:
587 			if (mh->handlers->server_push == NULL) {
588 				mh->handlers->server_push = ecalloc(1, sizeof(php_curlm_server_push));
589 			} else if (!Z_ISUNDEF(mh->handlers->server_push->func_name)) {
590 				zval_ptr_dtor(&mh->handlers->server_push->func_name);
591 				mh->handlers->server_push->fci_cache = empty_fcall_info_cache;
592 			}
593 
594 			ZVAL_COPY(&mh->handlers->server_push->func_name, zvalue);
595 			mh->handlers->server_push->method = PHP_CURL_USER;
596 			error = curl_multi_setopt(mh->multi, option, _php_server_push_callback);
597 			if (error != CURLM_OK) {
598 				return 0;
599 			}
600 			error = curl_multi_setopt(mh->multi, CURLMOPT_PUSHDATA, mh);
601 			break;
602 #endif
603 		default:
604 			php_error_docref(NULL, E_WARNING, "Invalid curl multi configuration option");
605 			error = CURLM_UNKNOWN_OPTION;
606 			break;
607 	}
608 
609 	SAVE_CURLM_ERROR(mh, error);
610 	if (error != CURLM_OK) {
611 		return 1;
612 	} else {
613 		return 0;
614 	}
615 }
616 /* }}} */
617 
618 /* {{{ proto int curl_multi_setopt(resource mh, int option, mixed value)
619        Set an option for the curl multi handle */
PHP_FUNCTION(curl_multi_setopt)620 PHP_FUNCTION(curl_multi_setopt)
621 {
622 	zval       *z_mh, *zvalue;
623 	zend_long        options;
624 	php_curlm *mh;
625 
626 	ZEND_PARSE_PARAMETERS_START(3,3)
627 		Z_PARAM_RESOURCE(z_mh)
628 		Z_PARAM_LONG(options)
629 		Z_PARAM_ZVAL(zvalue)
630 	ZEND_PARSE_PARAMETERS_END();
631 
632 	if ((mh = (php_curlm *)zend_fetch_resource(Z_RES_P(z_mh), le_curl_multi_handle_name, le_curl_multi_handle)) == NULL) {
633 		RETURN_FALSE;
634 	}
635 
636 	if (!_php_curl_multi_setopt(mh, options, zvalue, return_value)) {
637 		RETURN_TRUE;
638 	} else {
639 		RETURN_FALSE;
640 	}
641 }
642 /* }}} */
643 #endif
644 
645 #endif
646 
647 /*
648  * Local variables:
649  * tab-width: 4
650  * c-basic-offset: 4
651  * End:
652  * vim600: noet sw=4 ts=4 fdm=marker
653  * vim<600: noet sw=4 ts=4
654  */
655