diff options
Diffstat (limited to 'ext/curl/multi.c')
-rw-r--r-- | ext/curl/multi.c | 219 |
1 files changed, 184 insertions, 35 deletions
diff --git a/ext/curl/multi.c b/ext/curl/multi.c index 4c56d5a458..488cfde224 100644 --- a/ext/curl/multi.c +++ b/ext/curl/multi.c @@ -49,6 +49,8 @@ #include <unistd.h> #endif +#define SAVE_CURLM_ERROR(__handle, __err) (__handle)->err.no = (int) __err; + /* {{{ proto resource curl_multi_init(void) Returns a new cURL multi handle */ PHP_FUNCTION(curl_multi_init) @@ -61,6 +63,7 @@ PHP_FUNCTION(curl_multi_init) mh = ecalloc(1, sizeof(php_curlm)); mh->multi = curl_multi_init(); + mh->handlers = ecalloc(1, sizeof(php_curlm_handlers)); zend_llist_init(&mh->easyh, sizeof(zval), _php_curl_multi_cleanup_list, 0); @@ -77,6 +80,7 @@ PHP_FUNCTION(curl_multi_add_handle) php_curlm *mh; php_curl *ch; zval tmp_val; + CURLMcode error = CURLM_OK; if (zend_parse_parameters(ZEND_NUM_ARGS(), "rr", &z_mh, &z_ch) == FAILURE) { return; @@ -97,7 +101,10 @@ PHP_FUNCTION(curl_multi_add_handle) zend_llist_add_element(&mh->easyh, &tmp_val); - RETURN_LONG((zend_long)curl_multi_add_handle(mh->multi, ch->cp)); + error = curl_multi_add_handle(mh->multi, ch->cp); + SAVE_CURLM_ERROR(mh, error); + + RETURN_LONG((zend_long) error); } /* }}} */ @@ -129,6 +136,29 @@ static int curl_compare_resources( zval *z1, zval *z2 ) /* {{{ */ } /* }}} */ +/* Used to find the php_curl resource for a given curl easy handle */ +static zval *_php_curl_multi_find_easy_handle(php_curlm *mh, CURL *easy) /* {{{ */ +{ + php_curl *tmp_ch; + zend_llist_position pos; + zval *pz_ch_temp; + + for(pz_ch_temp = (zval *)zend_llist_get_first_ex(&mh->easyh, &pos); pz_ch_temp; + pz_ch_temp = (zval *)zend_llist_get_next_ex(&mh->easyh, &pos)) { + + if ((tmp_ch = (php_curl *)zend_fetch_resource(Z_RES_P(pz_ch_temp), le_curl_name, le_curl)) == NULL) { + return NULL; + } + + if (tmp_ch->cp == easy) { + return pz_ch_temp; + } + } + + return NULL; +} +/* }}} */ + /* {{{ proto int curl_multi_remove_handle(resource mh, resource ch) Remove a multi handle from a set of cURL handles */ PHP_FUNCTION(curl_multi_remove_handle) @@ -137,6 +167,7 @@ PHP_FUNCTION(curl_multi_remove_handle) zval *z_ch; php_curlm *mh; php_curl *ch; + CURLMcode error = CURLM_OK; if (zend_parse_parameters(ZEND_NUM_ARGS(), "rr", &z_mh, &z_ch) == FAILURE) { return; @@ -150,7 +181,10 @@ PHP_FUNCTION(curl_multi_remove_handle) RETURN_FALSE; } - RETVAL_LONG((zend_long)curl_multi_remove_handle(mh->multi, ch->cp)); + error = curl_multi_remove_handle(mh->multi, ch->cp); + SAVE_CURLM_ERROR(mh, error); + + RETVAL_LONG((zend_long) error); zend_llist_del_element(&mh->easyh, z_ch, (int (*)(void *, void *))curl_compare_resources); } @@ -178,6 +212,7 @@ PHP_FUNCTION(curl_multi_select) int maxfd; double timeout = 1.0; struct timeval to; + CURLMcode error = CURLM_OK; if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|d", &z_mh, &timeout) == FAILURE) { return; @@ -193,7 +228,9 @@ PHP_FUNCTION(curl_multi_select) FD_ZERO(&writefds); FD_ZERO(&exceptfds); - curl_multi_fdset(mh->multi, &readfds, &writefds, &exceptfds, &maxfd); + error = curl_multi_fdset(mh->multi, &readfds, &writefds, &exceptfds, &maxfd); + SAVE_CURLM_ERROR(mh, error); + if (maxfd == -1) { RETURN_LONG(-1); } @@ -209,7 +246,7 @@ PHP_FUNCTION(curl_multi_exec) zval *z_still_running; php_curlm *mh; int still_running; - int result; + CURLMcode error = CURLM_OK; if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz/", &z_mh, &z_still_running) == FAILURE) { return; @@ -237,10 +274,11 @@ PHP_FUNCTION(curl_multi_exec) convert_to_long(z_still_running); still_running = Z_LVAL_P(z_still_running); - result = curl_multi_perform(mh->multi, &still_running); + error = curl_multi_perform(mh->multi, &still_running); ZVAL_LONG(z_still_running, still_running); - RETURN_LONG(result); + SAVE_CURLM_ERROR(mh, error); + RETURN_LONG((zend_long) error); } /* }}} */ @@ -304,35 +342,21 @@ PHP_FUNCTION(curl_multi_info_read) /* find the original easy curl handle */ { - zend_llist_position pos; - php_curl *ch; - zval *pz_ch; - - /* search the list of easy handles hanging off the multi-handle */ - for(pz_ch = (zval *)zend_llist_get_first_ex(&mh->easyh, &pos); pz_ch; - pz_ch = (zval *)zend_llist_get_next_ex(&mh->easyh, &pos)) { - - if ((ch = (php_curl *)zend_fetch_resource(Z_RES_P(pz_ch), le_curl_name, le_curl)) == NULL) { - RETURN_FALSE; - } - if (ch->cp == tmp_msg->easy_handle) { - - /* we are adding a reference to the underlying php_curl - resource, so we need to add one to the resource's refcount - in order to ensure it doesn't get destroyed when the - underlying curl easy handle goes out of scope. - Normally you would call zval_copy_ctor( pz_ch ), or - SEPARATE_ZVAL, but those create new zvals, which is already - being done in add_assoc_resource */ - Z_ADDREF_P(pz_ch); - - /* add_assoc_resource automatically creates a new zval to - wrap the "resource" represented by the current pz_ch */ - - add_assoc_zval(return_value, "handle", pz_ch); - - break; - } + zval *pz_ch = _php_curl_multi_find_easy_handle(mh, tmp_msg->easy_handle); + if (pz_ch != NULL) { + /* we are adding a reference to the underlying php_curl + resource, so we need to add one to the resource's refcount + in order to ensure it doesn't get destroyed when the + underlying curl easy handle goes out of scope. + Normally you would call zval_copy_ctor( pz_ch ), or + SEPARATE_ZVAL, but those create new zvals, which is already + being done in add_assoc_resource */ + Z_ADDREF_P(pz_ch); + + /* add_assoc_resource automatically creates a new zval to + wrap the "resource" represented by the current pz_ch */ + + add_assoc_zval(return_value, "handle", pz_ch); } } } @@ -377,12 +401,37 @@ void _php_curl_multi_close(zend_resource *rsrc) /* {{{ */ curl_multi_cleanup(mh->multi); zend_llist_clean(&mh->easyh); + if (mh->handlers->server_push) { + efree(mh->handlers->server_push); + } + if (mh->handlers) { + efree(mh->handlers); + } efree(mh); rsrc->ptr = NULL; } } /* }}} */ +/* {{{ proto int curl_multi_errno(resource mh) + Return an integer containing the last multi curl error number */ +PHP_FUNCTION(curl_multi_errno) +{ + zval *z_mh; + php_curlm *mh; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &z_mh) == FAILURE) { + return; + } + + if ((mh = (php_curlm *)zend_fetch_resource(Z_RES_P(z_mh), le_curl_multi_handle_name, le_curl_multi_handle)) == NULL) { + RETURN_FALSE; + } + + RETURN_LONG(mh->err.no); +} +/* }}} */ + #if LIBCURL_VERSION_NUM >= 0x070c00 /* Available since 7.12.0 */ /* {{{ proto bool curl_multi_strerror(int code) return string describing error code */ @@ -405,6 +454,83 @@ PHP_FUNCTION(curl_multi_strerror) /* }}} */ #endif +#if LIBCURL_VERSION_NUM >= 0x072C00 /* Available since 7.44.0 */ + +static int _php_server_push_callback(CURL *parent_ch, CURL *easy, size_t num_headers, struct curl_pushheaders *push_headers, void *userp) /* {{{ */ +{ + php_curl *ch; + php_curl *parent; + php_curlm *mh = (php_curlm *)userp; + size_t rval = CURL_PUSH_DENY; + php_curlm_server_push *t = mh->handlers->server_push; + zval *pz_parent_ch = NULL; + zval pz_ch; + zval headers; + zval retval; + zend_resource *res; + char *header; + int error; + zend_fcall_info fci = empty_fcall_info; + + pz_parent_ch = _php_curl_multi_find_easy_handle(mh, parent_ch); + if (pz_parent_ch == NULL) { + return rval; + } + + parent = (php_curl*)zend_fetch_resource(Z_RES_P(pz_parent_ch), le_curl_name, le_curl); + + ch = alloc_curl_handle(); + ch->cp = easy; + _php_setup_easy_copy_handlers(ch, parent); + + Z_ADDREF_P(pz_parent_ch); + + res = zend_register_resource(ch, le_curl); + ZVAL_RES(&pz_ch, res); + + size_t i; + array_init(&headers); + for(i=0; i<num_headers; i++) { + header = curl_pushheader_bynum(push_headers, i); + add_next_index_string(&headers, header); + } + + zend_fcall_info_init(&t->func_name, 0, &fci, &t->fci_cache, NULL, NULL); + + zend_fcall_info_argn( + &fci, 3, + pz_parent_ch, + &pz_ch, + &headers + ); + + fci.retval = &retval; + + error = zend_call_function(&fci, &t->fci_cache); + zend_fcall_info_args_clear(&fci, 1); + zval_dtor(&headers); + + if (error == FAILURE) { + php_error_docref(NULL, E_WARNING, "Cannot call the CURLMOPT_PUSHFUNCTION"); + } else if (!Z_ISUNDEF(retval)) { + if (CURL_PUSH_DENY != zval_get_long(&retval)) { + rval = CURL_PUSH_OK; + + /* we want to create a copy of this zval that we store in the multihandle structure element "easyh" */ + zval tmp_val; + ZVAL_DUP(&tmp_val, &pz_ch); + zend_llist_add_element(&mh->easyh, &tmp_val); + } else { + /* libcurl will free this easy handle, avoid double free */ + ch->cp = NULL; + } + } + + return rval; +} + +#endif + #if LIBCURL_VERSION_NUM >= 0x070f04 /* 7.15.4 */ static int _php_curl_multi_setopt(php_curlm *mh, zend_long option, zval *zvalue, zval *return_value) /* {{{ */ { @@ -426,13 +552,36 @@ static int _php_curl_multi_setopt(php_curlm *mh, zend_long option, zval *zvalue, #endif error = curl_multi_setopt(mh->multi, option, zval_get_long(zvalue)); break; +#if LIBCURL_VERSION_NUM > 0x072D00 /* Available since 7.46.0 */ + case CURLMOPT_PUSHFUNCTION: + if (mh->handlers->server_push == NULL) { + mh->handlers->server_push = ecalloc(1, sizeof(php_curlm_server_push)); + } else if (!Z_ISUNDEF(mh->handlers->server_push->func_name)) { + zval_ptr_dtor(&mh->handlers->server_push->func_name); + mh->handlers->server_push->fci_cache = empty_fcall_info_cache; + } + ZVAL_COPY(&mh->handlers->server_push->func_name, zvalue); + mh->handlers->server_push->method = PHP_CURL_USER; + if (!Z_ISUNDEF(mh->handlers->server_push->func_name)) { + zval_ptr_dtor(&mh->handlers->server_push->func_name); + mh->handlers->server_push->fci_cache = empty_fcall_info_cache; + + } + error = curl_multi_setopt(mh->multi, option, _php_server_push_callback); + if (error != CURLM_OK) { + return 0; + } + error = curl_multi_setopt(mh->multi, CURLMOPT_PUSHDATA, mh); + break; +#endif default: php_error_docref(NULL, E_WARNING, "Invalid curl multi configuration option"); error = CURLM_UNKNOWN_OPTION; break; } + SAVE_CURLM_ERROR(mh, error); if (error != CURLM_OK) { return 1; } else { |